Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 912
dinghao Avatar asked May 13 '14 04:05

dinghao


People also ask

What does Instanceof return in JavaScript?

The JavaScript instanceof operator is used to check the type of an object at the run time. It returns a boolean value(true or false). If the returned value is true, then it indicates that the object is an instance of a particular class and if the returned value is false then it is not.

What is the difference between Typeof and Instanceof operators in JavaScript?

typeof: Per the MDN docmentation, typeof is a unary operator that returns a string indicating the type of the unevaluated operand. instanceof: is a binary operator, accepting an object and a constructor. It returns a boolean indicating whether or not the object has the given constructor in its prototype chain.

How do you check if an object is an instance of?

Using isinstance() function, we can test whether an object/variable is an instance of the specified type or class such as int or list. In the case of inheritance, we can checks if the specified class is the parent class of an object. For example, isinstance(x, int) to check if x is an instance of a class int .

Is array an object Instanceof?

Short answer: Array instanceof Object is true because functions are objects and every object has Object.


2 Answers

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.

like image 120
thefourtheye Avatar answered Sep 19 '22 12:09

thefourtheye


From MDN:

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

Essentially, it is checking if Object (not an instance of Object, but the constructor itself) has as an instance of Function.constructor somewhere up its prototype chain.

And, indeed:

> Function.__proto__.__proto__ === Object.prototype true > Object.__proto__ === Function.prototype true 

This explains why Object instanceof Function as well as the reverse.

like image 45
Andrew Eisenberg Avatar answered Sep 17 '22 12:09

Andrew Eisenberg