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.

Original source