1

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)?

1
  • 2
    Your first example doesn't use prototypical inheritance, that's why. Commented Nov 10, 2020 at 20:30

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Lots of thanks for a 100% informative and clear answer! You've helped me a lot.
Is it OK to use "Object.setPrototypeOf(Child.prototype, Parent.prototype);" instead of "Child.prototype = Object.create(Parent.prototype);" (in your example)? I tried, it works. And the difference is in the following: when I use "setPrototypeOf" and then check in the console "Object.getOwnPropertyNames(Child.prototype)", I can see the constructor property inside, but when I use "Object.create" (like in your example), this check does not show the constructor.
Sorry for bothering you again ... but why the results of "Object.getOwnPropertyNames(Child.prototype)" are different if to use "Object.setPrototypeOf(Child.prototype, Parent.prototype);" and "Child.prototype = Object.create(Parent.prototype);"? See above (I've just edited the comment).
"Object.setPrototypeOf(Child.prototype, Parent.prototype);" seems to be the same as "Child.prototype.__proto__ = Parent.prototype;", but different from "Child.prototype = Object.create(Parent.prototype);": in the first two cases, constructor is shown when to check "Object.getOwnPropertyNames(Child.prototype)"; in the third case, Child seems to lose its own constructor property...
That's because the Child.prototype which JS automatically creates for you includes, a constructor property. The first two examples simply change that object's prototype, whereas the one with Object.create overrides the object completely (creates a completely empty object with the correct prototype).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.