I just cannot understand, why in object inheritance “instanceof” fails to evaluate “children”-objects as instances of parent prototypes. For example:
function Parent(property) { this.property = property; } function Child(property) { Parent.call(property); } const child = new Child(""); console.log(child instanceof Child); // of course, true console.log(child instanceof Parent); // false. But why???
As for inheritance of classes (or rather of what is deemed to be classes in JS), the situation is different:
class Parent { constructor(property) { this.property = property; } } class Child extends Parent { constructor(property) { super(property); } } const child = new Child(""); console.log(child instanceof Child); // true console.log(child instanceof Parent); // also true!!!
What is the cause of this difference? Is it possible to create children-objects so that they were correctly recognised as instances of their parent prototypes (without resorting to classes)?
Advertisement
Answer
Your first example is, quite simply, not remotely close to how “prototypal inheritance” works in Javascript.
For one thing, Parent.call(property)
surely isn’t what you meant. This calls Parent
with its this
set to property
, and no arguments passed, which definitely isn’t what you want. I suspect you mean Parent.call(this, property)
– which calls Parent
with the same this
as is passed to Child
, and passing through the property
argument. But this isn’t anything to do with “inheritance”.
The instanceof operator simply checks an object’s “prototype chain” to see if the relevant object (the prototype
property of the “class” you’re testing against) appears anywhere. The only way to manipulate objects to affect the instanceof
operator is to alter the prototype chain.
There are a number of ways to do this, but the standard way to “fake” something like class-based inheritance in JS, pre-ES6, would have been like this:
function Parent(property) { this.property = property; } function Child(property) { } Child.prototype = Object.create(Parent.prototype); const child = new Child(""); console.log(child instanceof Child); console.log(child instanceof Parent);
which manually makes all objects constructed from Child
delegate to Object.create(Parent.prototype)
, which itself is an object (one otherwise completely empty and with no special properties) that “inherits” from Parent.prototype
. So now when instanceof
checks the prototype chain, it finds what it’s looking for, and therefore returns true
, as you can see from the above snippet.
Of course, if you really do want class-based inheritance in JS (which I personally wouldn’t recommend, but is certainly popular), the ES6 class
syntax gives a much nicer syntactic sugar so you don’t have to manually mess with the prototype chain as above. But be aware that that’s essentially what’s going on “under the hood” with ES6 classes.
I strongly recommend this book (freely available to read online) for much deeper explanations of all this. Chapter 5 is the most relevant one in this context.