Why in JavaScript do both Object instanceof Function and Function instanceof Object return true?
I tried it in Safari WebInspector.
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.
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.
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 .
Short answer: Array instanceof Object is true because functions are objects and every object has Object.
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
instanceofoperator tests whether an object has in its prototype chain theprototypeproperty of a constructor.
[instanceof]Now, let us see how instanceof is defined by ECMA 5.1 Specification,
The production
RelationalExpression: RelationalExpression instanceof ShiftExpressionis evaluated as follows:
- Let
lrefbe the result of evaluatingRelationalExpression.- Let
lvalbeGetValue(lref).- Let
rrefbe the result of evaluatingShiftExpression.- Let
rvalbeGetValue(rref).- If
Type(rval)is not Object, throw aTypeErrorexception.- If
rvaldoes not have a[[HasInstance]]internal method, throw aTypeErrorexception.- Return the result of calling the
[[HasInstance]]internal method ofrvalwith argumentlval.
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
Fis a Function object.When the
[[HasInstance]]internal method ofFis called with valueV, the following steps are taken:
- If
Vis not an object, returnfalse.- Let
Obe the result of calling the[[Get]]internal method ofFwith property name"prototype".- If
Type(O)is not Object, throw aTypeErrorexception.- Repeat
- Let
Vbe the value of the[[Prototype]]internal property ofV.- If
Visnull, returnfalse.- If
OandVrefer to the same object, returntrue.
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 propertyFirst let us see what is the [[prototype]] internal property,
All objects have an internal property called
[[Prototype]]. The value of this property is eithernullor 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 anullvalue).
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
prototypeproperty 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 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With