instanceof check works on subclass without setting constructor [duplicate]

I have the following JavaScript code

function Parent() {
}

function Child() {
}

Child.prototype = Object.create(Parent.prototype);

Note the absence of the statement

Child.prototype.constructor = Child;

My understanding is that as the constructor property has not been set the instanceof checks should fail for new instances of Child class.

var child = new Child();
child instanceof Child; //Should give false

I verified that the constructor is incorrectly set enter image description here

But when I run child instanceof Child it gave me true

enter image description here

But it should be false as constructor property is not set on Child's prototype to be Child.

Environment

Google Chrome Version 48.0.2564.109 (64-bit)
Ubuntu 14.04 LTS

Answers:

Answer

My understanding is that as the constructor property has not been set the instanceof checks should fail for new instances of Child class.

No, that's incorrect. In fact, until ES2015 (aka ES6), the constructor property wasn't used for anything at all in JavaScript itself. It was defined as existing on the default objects the runtime assigns to the prototype property on functions, but not used.

instanceof doesn't care about construtor at all. Consider:

o instanceof Foo

instanceof will look to see if the object Foo.prototype points to is anywhere on o's prototype chain. (If "prototype chain" is not a familiar term, see the * at the end of the answer and then come back.) If so, it returns true; if not, it returns false.

E.g., here's a conceptual implementaton of instanceof, hand-waving away some details:

function isAnInstance(obj, func) {
    var p;
    for (p = Object.getPrototypeOf(obj); p; p = Object.getPrototypeOf(p)) {
        if (p === func.prototype) {
            return true;
        }
    }
    return false;
}

Although it's been superceded by the ES2015 spec, I'll link to the ES5 spec because it's written in more accessible language and this aspect hasn't changed: instanceof effectively just calls a function's [[HasInstance]] internal method, defined here.

We can see that constructor isn't involved from your question, and also from this simple demonstration:

var p = {};
var o = Object.create(p);
var Foo = function() {};
Foo.prototype = p;
snippet.log(o instanceof Foo); // true
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Note that:

  1. o wasn't created via Foo
  2. In fact, Foo didn't even exist until after o was created
  3. o and its prototype don't have a constructor property at all

...and yet instanceof says "Yep, looks like it's a Foo." :-) Purely because the object Foo.prototype points to is also on o's prototype chain.


* "prototype chain"

You clearly know that objects in JavaScript have prototypes from which they inherit properties. Those prototypes are objects, and so they have prototypes. So you get a "chain" of prototypes.

Consider a two-level (arguably three-level) inheritance hierarchy, here in ES5:

function Base() {
}

function Derived() {
    Base.call(this);
}
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;

...or in ES2015:

class Base {
}
class Derived extends Base {
}

Now we use it:

var d = new Derived();

(Where you see "the d object" and similar in the below, I do of course mean "the object d refers to" — but that's really verbose.)

Now, the d object's prototype is Derived.prototype. Derived.prototype's prototype is Base.prototype. Base.prototype's prototype is Object.prototype. Object.prototype doesn't have a prototype (its [[Prototype]] internal slot is null).

Those objects are the prototype chain underlying d, and they mean that d is instanceof Object, instanceof Base, and instanceof Derived.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.