Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
206 views
in Technique[技术] by (71.8m points)

Why in JavaScript both "Object instanceof Function" and "Function instanceof Object" return true?

Why in JavaScript do both Object instanceof Function and Function instanceof Object return true?

I tried it in Safari WebInspector.

question from:https://stackoverflow.com/questions/23622695/why-in-javascript-both-object-instanceof-function-and-function-instanceof-obj

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It took a while for me to figure out but its really worth the time spent. First, let us see how instanceof works.

Quoting from MDN,

The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

[instanceof]

Now, let us see how instanceof is defined by ECMA 5.1 Specification,

The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating ShiftExpression.
  4. Let rval be GetValue(rref).
  5. If Type(rval) is not Object, throw a TypeError exception.
  6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
  7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

First the left and right hand side expressions are evaluated (GetValue) and then right hand side result should be an Object with [[HasInstance]] internal method. Not all objects will have [[HasInstance]] internal method, but functions. For example, the following will fail

console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>

[[HasInstance]]

Now, let us see how [[HasInstance]] has been defined in the ECMA 5.1 specification,

Assume F is a Function object.

When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:

  1. If V is not an object, return false.
  2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
  3. If Type(O) is not Object, throw a TypeError exception.
  4. Repeat
    1. Let V be the value of the [[Prototype]] internal property of V.
    2. If V is null, return false.
    3. If O and V refer to the same object, return true.

It is so simple. Take the prototype property of F and compare it with the [[Prototype]] internal property of O until it becomes null or prototype of F is the same as O.

[[prototype]] internal property

First let us see what is the [[prototype]] internal property,

All objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. Whether or not a native object can have a host object as its [[Prototype]] depends on the implementation. Every [[Prototype]] chain must have finite length (that is, starting from any object, recursively accessing the [[Prototype]] internal property must eventually lead to a null value).

Note: We can get this internal property with the Object.getPrototypeOf function.

prototype property

[[HasInstance]] also talks about another property called prototype, which is specific to the Function objects.

The value of the prototype property is used to initialise the [[Prototype]] internal property of a newly created object before the Function object is invoked as a constructor for that newly created object.

This means that, when a function object is used as a constructor, a new object will be created and the new object will have its internal [[Prototype]] initialized with this prototype property. For example,

function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true

Actual problem

Now let us get back to the actual question. Lets take the first case

console.log(Object instanceof Function);
# true

It will fetch Function.prototype first and it will try and find if that object is in the prototype hierarchy of Object. Let us see how that turns out

console.log(Function.prototype);
# [Function: Empty]
console.log(Object.getPrototypeOf(Object));
# [Function: Empty]
console.log(Object.getPrototypeOf(Object) === Function.prototype);
# true

Since the Function.prototype matches the Object's internal property [[Prototype]], it returns true.

Now lets take the second case

console.log(Function instanceof Object);
# true
console.log(Object.prototype);
# {}
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
# true

Here, first we get the Object.prototype, which is {}. Now it is trying to find if the same object {} is there in the Function's prototype chain. Immediate parent of Function is and Empty function.

console.log(Object.getPrototypeOf(Function));
# [Function: Empty]

It is not the same as Object.prototype

console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false

But the [[HasInstance]] algorithm doesn't stop there. It repeats and gets up one more level

console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}

And this is the same as Object.prototype. That is why this returns true.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...