Function and Object, instances of each other
Explaining why Function is an instance of Object, and why Object is an instance of Function
Before jumping straight into the explanation, we should first quickly cover two topics: the difference between the internal [[Prototype]] property and the external prototype property, and their relationship to each other. Of course, you can always jump ahead to the crux of the explanation.
Internal [[Prototype]] and external prototype
For brevity, I will not outline the details of the instanceof operator (you can always check the ECMAScript specification), but at a high level, it simply tests whether an object has in its prototype chain the prototype property of a constructor. But testing the prototype chain does not mean looking up the external prototype property which everyone is familiar with— it refers to the internal [[Prototype]] 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.
Being an internal property, [[Prototype]] is not directly accessible, however, it can be interacted with using Object.getPrototypeOf. This internal property is present for all objects, handling property and method lookups.
In contrast, the external prototype property is specific to Function objects:
The value of the prototype property is used to initialize 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 the prototype is the object that is used to build [[Prototype]] when you create an object using the new keyword. In other words, when a function object is used as a constructor, a new object will be created and the new object will have its [[Prototype]] initialized with its prototype property.
Take the following example:
// Function object that will be used as a constructor
function Car(){}// Car.prototype has a single property called "constructor"
// which points back to Car
Car.prototype.constructor === Car // true// Car.prototype is an object
// console.log(Car.prototype) => Object {}
Car.prototype instanceof Object // true// Create an object using the new keyword
var myCar = new Car()// The internal [[Prototype]] of `myCar` is initialized
// with `Car.prototype`
Object.getPrototypeOf(myCar) === Car.prototype // true
With the above snippet we can state the following points:
- Car.prototype points to an automatically created new object. This is what JavaScript does by default when you declare a function.
- Car.prototype is empty except for a constructor property which points back to the constructor function itself
- Car.prototype is an instance of an object.
- myCar’s [[Prototype]] is Car.prototype.
- The next object in myCar’s prototype (i.e, [[Prototype]]) chain is Car.prototype.
The last line (Object.getPrototypeOf(myCar) === Car.prototype) demonstrates that myCar is indeed an instance of Car. We can verify this programmatically:
myCar instanceof Car // true
We can see here how the instanceOf operator keeps walking up at the prototype chain to determine whether the left hand side’s [[Prototype]] is equal to the right hand side’s prototype.
Now that we understand the relationship between [[Prototype]] and prototype, let’s go back and examine why Function and Object are instances of each other.
Function instanceof Object
var internalProto
internalProto = Object.getPrototypeOf(Function)
internalProto === Object.prototype // false
// Since it’s false, move up the prototype chain
internalProto = Object.getPrototypeOf(internalProto)
internalProto === Object.prototype // true
// Since it’s true, no need to move up the chain
Remember that all objects in JavaScript are descended from Object. This also includes Function:
When Function is called as a function rather than as a constructor, it creates and initializes a new Function object. Thus the function call Function(…) is equivalent to the object creation expression new Function(…) with the same arguments.
Additionally, Function.prototype gets initialized to the same function as its [[Prototype]] property:
Every built-in function and every built-in constructor has the Function prototype object, which is the initial value of the expression Function.prototype as the value of its [[Prototype]] internal property.
All this means the following:
Function.prototype // function () {}
Object.getPrototypeOf(Function) // function () {}// They point to the same function
Object.getPrototypeOf(Function) === Function.prototype // true
Therefore, since Function.prototype is a function, and since every function is an Object, then its [[Prototype]] property must eventually resolve to Object.prototype. Since it resolves to Object.prototype, then Function instanceof Object holds true.
Object instanceof Function
var internalProto
internalProto = Object.getPrototypeOf(Object)
internalProto === Function.prototype // true
// Since it’s true, no need to move up the chain
When we say Object, we’re referring to the Object constructor. The constructor is indeed a function. Its behavior is outlined in the specification. However, the most important thing, with respect to its relationship to Function, is this statement:
The value of the [[Prototype]] internal property of the Object constructor is the standard built-in Function prototype object.
Therefore, since Object’s [[Prototype]] is Function.prototype, and since Function.prototype is a function, then Object instanceof Function holds true.
I hope this has clarified the ambiguity. If something is unclear, please post a response. Cheers!