x.__proto__ == X.prototype is not always same as x instanceof X in javascript?

100 views Asked by At

I know that one should not use __proto__ directly in the code, but just out of curiosity I was playing around with this in node. I was under the impression that if x.__proto__ == X.prototype then it means x instanceof X will yield true until I hit this code with primitive values.

> (2).__proto__ ==  Number.prototype
true
> 2 instanceof Number
false
> (2) instanceof Number
false


> "abc".__proto__ == String.prototype
true
> "abc" instanceof String
false
> ("abc") instanceof String
false

Why is this?

2

There are 2 answers

0
T.J. Crowder On BEST ANSWER

instanceof will always yield false if the left-hand side is not an object (see Step 3 here).

The reason (2).__proto__ == Number.prototype is true is that when you apply a property accessor to a primitive (in this case, .__proto__), a temporary object with the same underlying primitive value is created and used.

So the thing you're getting the __proto__ property from isn't the same thing you're using in your instanceof cases, because it isn't a primitive. Your test cases would more accurately be:

> (2).__proto__ == Number.prototype
true
> new Number(2) instanceof Number
true

I was under the impression that if x.__proto__ == X.prototype then it means x instanceof X will yield true

That's true as far as it goes (or would be if you used ===, for a fairly obscure reason1), but note that the converse is not true: If x instanceof X is true, that doesn't necessarily mean x.__proto__ == X.prototype will be true, for a couple of reasons:

  1. It could be that you need to use x.__proto__.__proto__, or x.__proto__.__proto__.__proto__, or... :-)

  2. x.__proto__ may well be undefined. For instance, it is if you create x like this: x = Object.create(null). The reason is that the __proto__ property accessor is provided by Object.prototype, but if you create an object that doesn't inherit from Object.prototype, it doesn't have the __proto__ property accessor (on a compliant implementation). This is one reason to use Object.getPrototypeOf(x) instead.


1 Fairly obscure reason: If x was created via Object.create(null) (or using any prototype that doesn't trace back to Object.prototype) and thus doesn't have the __proto__ property accessor, and X.prototype is null, x.__proto__ == X.prototype would be true even though they could well be completely and utterly unrelated, since x.__proto__ would be undefined and undefined == null is true. ;-)

0
Oriol On

Primitive values are not objects, and thus are not instances of any constructor.

Your checks will work if you coerce the values to objects:

console.log(Object(2) instanceof Number); // true
console.log(Object("abc") instanceof String); // true
console.log(Object(true) instanceof Boolean); // true
console.log(Object(Symbol()) instanceof Symbol); // true