Consider the following code.
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
- Why isn’t the constructor updated for b and c?
- Am I doing inheritance wrong?
- What is the best way to update the constructor?
Further, please consider the following.
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
- Given that
(new c()).constructoris equal toa()andObject.getPrototypeOf(new c())isa{ }, how is it possible forinstanceofto know thatnew c()is an instance ofc?
Okay, let’s play a little mind game:
From the above image we can see:
function Foo() {}, JavaScript creates aFunctioninstance.Functioninstance (the constructor function) has a propertyprototypewhich is a pointer.prototypeproperty of the constructor function points to its prototype object.constructorwhich is also a pointer.constructorproperty of the prototype object points back to its constructor function.Foolikenew Foo(), JavaScript creates a new object.[[proto]]property of the instance points to the prototype of the constructor.Now, the question arises that why doesn’t JavaScript attach the
constructorproperty to the instance object instead of the prototype. Consider:As you can see the
constructorproperty is just another method of the prototype, likeareain the example above. What makes theconstructorproperty special is that it’s used to initialize an instance of the prototype. Otherwise it’s exactly the same as any other method of the prototype.Defining the
constructorproperty on the prototype is advantageous for the following reasons:Object.prototype. Theconstructorproperty ofObject.prototypepoints toObject. If theconstructorproperty was defined on the instance thenObject.prototype.constructorwould beundefinedbecauseObject.prototypeis an instance ofnull.neweasier since it doesn’t need to define theconstructorproperty on every instance.constructorproperty. Hence it’s efficient.Now when we talk about inheritance, we have the following scenario:
From the above image we can see:
prototypeproperty is set to the instance of the base constructor.[[proto]]property of the instance of the derived constructor points to it too.constructorproperty of the derived constructor instance now points to the base constructor.As for the
instanceofoperator, contrary to popular belief it doesn’t depend on theconstructorproperty of the instance. As we can see from above, that would lead to erroneous results.The
instanceofoperator is a binary operator (it has two operands). It operates on an instance object and a constructor function. As explain on Mozilla Developer Network, it simply does the following:To put it simply if
Fooinherits fromBar, then the prototype chain for the instance ofFoowould be:foo.__proto__ === Foo.prototypefoo.__proto__.__proto__ === Bar.prototypefoo.__proto__.__proto__.__proto__ === Object.prototypefoo.__proto__.__proto__.__proto__.__proto__ === nullAs you can see, every object inherits from the
Objectconstructor. The prototype chain ends when an internal[[proto]]property points tonull.The
instanceoffunction simply traverses the prototype chain of the instance object (the first operand) and compares the internal[[proto]]property of each object to theprototypeproperty of the constructor function (the second operand). If they match, it returnstrue; and else if the prototype chain ends, it returnsfalse.