Object Inheritance in JavaScript

inheritance, javascript, prototype

Solution

In the code John Resig provided he first sets `Ninja.prototype` to `Person.prototype`. Then he immediately resets it to `{ dance: Person.prototype.dance }`:

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;
Ninja.prototype = { dance: Person.prototype.dance };

The result is that any object created by the `Ninja` constructor will directly inherit from `{ dance: Person.prototype.dance }` which is not an instance of `Person.prototype`. Hence `(new Ninja) instanceof Person` will return false. In this case the prototype chain is:

        null
         ^
         |
         | [[prototype]]
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|  Ninja.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|     new Ninja    |
+------------------+

In the modified version you remove the second assignment to `Ninja.prototype`, effectively setting `Ninja.prototype` to `Person.prototype`. Hence the prototype chain is:

         null
          ^
          |
          | [[prototype]]
          |
+-------------------+
|  Object.prototype |
+-------------------+
          ^
          |
          | [[prototype]]
          |
+-------------------+
| Ninja.prototype / |
| Person.prototype  |
+-------------------+
          ^
          |
          | [[prototype]]
          |
+-------------------+
|     new Ninja     |
+-------------------+

Notice that since `Ninja.prototype` is the same as `Person.prototype` both `(new Ninja) intanceof Ninja` and `(new Ninja) instanceof Person` will return `true`. This is because the `instanceof` operator depends on the `prototype` of a constructor.

However the right way to do achieve inheritance in JavaScript would be to set `Ninja.prototype` to `Object.create(Person.prototype)` (or in the old school way to `new Person`), in which case the prototype chain would be:

        null
         ^
         |
         | [[prototype]]
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
| Person.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|  Ninja.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|     new Ninja    |
+------------------+

Note: Always remember that in JavaScript objects inherit from other objects. They never inherit from constructor functions. If you wish to learn about true prototypal inheritance in JavaScript then read my blog post on why prototypal inhritance matters.

Problem

My question is regarding a child object maintaining the prototype chain of its parent object. In John Resig's Advanced Javascript slides (http://ejohn.org/apps/learn/#76) he writes that in order to maintain the prototype chain of a child object you must instantiate a new parent object. However through a couple quick tests I noticed that the prototype chain is maintained by just setting the child object prototype equal to the parent object prototype. Any clarification would be greatly appreciated! Original Code ``` function Person(){} Person.prototype.dance = function(){}; function Ninja(){} // Achieve similar, but non-inheritable, results Ninja.prototype = Person.prototype; Ninja.prototype = { dance: Person.prototype.dance }; assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." ); // Only this maintains the prototype chain Ninja.prototype = new Person(); var ninja = new Ninja(); assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" ); assert( ninja instanceof Person, "... and the Person prototype" ); assert( ninja instanceof Object, "... and the Object prototype" ); ``` My Modified Version ``` function Person(){} Person.prototype.dance = function(){console.log("Dance")}; function Ninja(){} // Achieve similar, but non-inheritable, results Ninja.prototype = Person.prototype; assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." ); var ninja = new Ninja(); assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" ); assert( ninja instanceof Person, "... and the Person prototype" ); assert( ninja instanceof Object, "... and the Object prototype" ); ninja.dance(); ```

Original source

Related problems