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
instanceof
operator tests whether an object has in its prototype chain theprototype
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:
- Let
lref
be the result of evaluatingRelationalExpression
.- Let
lval
beGetValue(lref)
.- Let
rref
be the result of evaluatingShiftExpression
.- Let
rval
beGetValue(rref)
.- If
Type(rval)
is not Object, throw aTypeError
exception.- If
rval
does not have a[[HasInstance]]
internal method, throw aTypeError
exception.- Return the result of calling the
[[HasInstance]]
internal method ofrval
with 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
F
is a Function object.When the
[[HasInstance]]
internal method ofF
is called with valueV
, the following steps are taken:
- If
V
is not an object, returnfalse
.- Let
O
be the result of calling the[[Get]]
internal method ofF
with property name"prototype"
.- If
Type(O)
is not Object, throw aTypeError
exception.- Repeat
- Let
V
be the value of the[[Prototype]]
internal property ofV
.- If
V
isnull
, returnfalse
.- If
O
andV
refer 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 eithernull
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 anull
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
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