When a prototype is set on a constructor function, the instanceof operator only returns true until the prototype is changed. Why?
function SomeConstructorFunction() {
}
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = {}; //Can be any prototype
return new constructorFn();
}
var child1 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //true
var child2 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //false
console.log(child2 instanceof SomeConstructorFunction); //true
Prototypal inheritance can be a bit of a brain bender. I've already written a simple explanation for prototypal inheritance in the following answer and I suggest you read it: https://stackoverflow.com/a/8096017/783743
Now to answer your question. Consider the following function:
function F() {}
I can create an instance of F using new as follows:
var f = new F;
As expected f instanceof F returns true. This is because the instanceof operator checks for F.prototype in the prototype chain of f and returns true if it is there. See the answer I linked to above.
Now say I create a new function G as follows and set F.prototype to G.prototype:
function G() {}
F.prototype = G.prototype;
If I now evaluate f instanceof F again false is returned. This is because F.prototype is no longer in the prototype chain of f (remember that F.prototype is now G.prototype).
Now let's create a new instance of F:
var g = new F;
If you evaluate g instanceof G it'll return true even though g = new F. This is because G.prototype exists in the prototype chain of g.
This is not a bug. It's the way JavaScript works. In fact we can exploit this feature to create some really interesting functions: Instantiate JavaScript functions with custom prototypes
constructorFn.prototype = {}; //Can be any prototype
Not true!
constructorFn.prototype = Object.prototype;
Or any other native prototype will make them all true.
The reason is that the first time that you're calling extendAndInstantiate(), you're setting the SomeConstructorFunction's prototype to something (here an empty object {}). For child1, instanceOf will only return true while SomeConstructorFunction's prototype is that exact instance of {}. When you run extendAnInstantiate() a second time, you're changing SomeConstructorFunction's prototype to a different instance of {}, so child2 will be an instanceOf that new {}, but child1 is still an instanceOf of the old {}, so child1 will return false, while child2 returning true. If you set the prototype to a common prototype, such as Object.prototype or Array.prototype, it will always return true.
Another way to illustrate this is to pull {} out of the function, and assign it to a variable obj.
var obj = {};
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = obj;
return new constructorFn();
}
Now this will always return true, because you aren't creating a new {} every time you run the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With