How does instanceof work in JavaScript?
In the following code sample both checks of obj2 and obj3 at the end with instanceof return true even if the ways there were constructed are different and the results of returning name property are different.
var Obj1 = function() {
this.name = "foo1";
};
Obj1.prototype.name = "foo1onProt";
var obj1 = new Obj1();
var Obj2 = function() {};
Obj2.prototype = new Obj1();
Obj2.prototype.constructor = Obj2;
var obj2 = new Obj2();
var Obj3 = function() {};
Obj3.prototype = Object.create(Obj1.prototype);
Obj3.prototype.constructor = Obj3;
var obj3 = new Obj3();
console.dir(obj1);
console.log("obj1.name: " + obj1.name);
console.dir(obj2);
console.log("obj2.name: " + obj2.name);
console.dir(obj3);
console.log("obj3.name: " + obj3.name);
console.log("obj2 instanceof Obj1: " + (obj2 instanceof Obj1));
console.log("obj3 instanceof Obj1: " + (obj3 instanceof Obj1));
Result of the run in Chrome:
Obj1
name: "foo1"
__proto__: Object
constructor: function () {
name: "foo1onProt"
__proto__: Object
obj1.name: foo1
Obj2
__proto__: Obj1
constructor: function () {}
name: "foo1"
__proto__: Object
constructor: function () {
name: "foo1onProt"
__proto__: Object
obj2.name: foo1
Obj3
__proto__: Object
constructor: function () {}
__proto__: Object
constructor: function () {
name: "foo1onProt"
__proto__: Object
obj3.name: foo1onProt
obj2 instanceof Obj1: true
obj3 instanceof Obj1: true
What is the best way to recognize that obj2 and obj3 are different? How does actually instanceof work?
What is the best way to recognize that obj2 and obj3 are different?
That will depend a great deal on what you're doing with them. One way would be to use instanceof Obj2
and instanceof Obj3
. Since both objects were created with Obj1.prototype
in their prototype chain, it makes sense that they identify as being an instance of what we would call the supertype in class-based OOP.
How does actually instanceof work?
The short version
obj instanceof F
looks to see if the object referenced by F.prototype
is anywhere in obj
's prototype chain. It doesn't use constructor
at all.
More details
This is covered in the spec by §11.8.5 - The instanceof Operator, which says (indirectly, via §8.6.2) that it calls the [[HasInstance]]
internal method of the function object, passing in the object we're testing. Function
's [[HasInstance]]
(in §15.3.5.3) says that it gets the object reference from the function's prototype
property and then returns true
if that object is anywhere in the target object's prototype chain, false
if it doesn't.
It doesn't use constructor
(nothing in JavaScript itself does, in fact) — and if you think about it, it can't, because an object's constructor
property can only point at one function, but an object can be instanceof
multiple functions — for instance, in the case of pseudo-classical inheritance:
function F1() {}
function F2() {
F1.call(this);
}
F2.prototype = Object.create(F1.prototype);
F2.prototype.constructor = F2;
var obj = new F2();
console.log(obj instanceof F1); // true
console.log(obj instanceof F2); // true
Both are true because the two objects referenced by F1.prototype
and F2.prototype
are both in obj
's prototype chain.
instanceof
being true doesn't necessarily mean that obj
was created by a call to F
, either directly or indirectly; it just indicates there's a vague link between them (F.prototype
refers to an object that's also in obj
's prototype chain). It usually means F
was involved in creating the object, but there's no guarantee.
For instance:
function F() {}
var obj = Object.create(F.prototype);
console.log(obj instanceof F); // true
Note that F
wasn't called to create the object, at all.
Or perhaps more clearly and/or dramatically:
function F() {}
var p = {};
var obj = Object.create(p);
console.log(obj instanceof F); // false
F.prototype = p;
console.log(obj instanceof F); // true
There's also this unusual, but entirely possible, version:
function F1() {}
function F2() {}
F1.prototype = F2.prototype = {};
var obj = new F1();
console.log(obj instanceof F2); // true
Or this one:
function F1() {}
function F2() {}
var obj = new F2();
console.log(obj instanceof F1); // false
F1.prototype = F2.prototype;
console.log(obj instanceof F1); // true
Most simply: obj instanceof constructor
yields true
when obj
has constructor
's prototype in it's constructor/prototype chain. In other words, your asking your engine whether obj
can be treated like an instance of constructor
/ whether obj
behaves like a constructor
object.
There is a small handful of syntaxes that allow you to put constructor
's prototype in obj
's prototype chain. Any and all of them will cause obj instanceof constructor
to be true
. In your examples, both obj2
and obj3
have Obj1
in their prototype chain.
So, when you ask your javascript engine whether either obj2
or obj3
behave like an instance of Obj1
, JavaScript assumes true
-- the only case wherein they wouldn't is if you've overridden Obj1
's behavior down the line.