Why in JavaScript both "Object instanceof Function" and "Function instanceof Object" return true?
function, javascript, object
Solution
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:
- Let `lref` be the result of evaluating `RelationalExpression`.
- Let `lval` be `GetValue(lref)`.
- Let `rref` be the result of evaluating `ShiftExpression`.
- Let `rval` be `GetValue(rref)`.
- If `Type(rval)` is not Object, throw a `TypeError` exception.
- If `rval` does not have a `[[HasInstance]]` internal method, throw a `TypeError` exception.
- 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:
- If `V` is not an object, return `false`.
- Let `O` be the result of calling the `[[Get]]` internal method of `F` with property name `"prototype"`.
- If `Type(O)` is not Object, throw a `TypeError` exception.
- Repeat
- Let `V` be the value of the `[[Prototype]]` internal property of `V`.
- If `V` is `null`, return `false`.
- 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`.
Problem
Why in JavaScript do both `Object instanceof Function` and `Function instanceof Object` return `true`? I tried it in Safari WebInspector.