问题
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
But when I run child instanceof Child
it gave me true
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
回答1:
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:
o
wasn't created viaFoo
- In fact,
Foo
didn't even exist until aftero
was created o
and its prototype don't have aconstructor
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
.
来源:https://stackoverflow.com/questions/35537995/instanceof-check-works-on-subclass-without-setting-constructor