Constructor and Object model
In this post, we will figure out briefly what happens internally when we call a constructor.
It will be needed necessary to understand JS object model and 'this' keyword later.
1. Review
Definition of the constructor :
- It is a function
- It creates an instance and returns it
Yes, the constructor is just a function.
If we do not use 'new' keyword, it is just executed and finished without returning the instance.
So whether to call the function using the keyword 'new', shows different results.
2. Keyword 'new'
First, here is a sample code of Person object.
function Person(name) {
this.name = name;
}
Person.prototype.walk = function() {
console.log(this.name + ' walks');
}
var me = new Person('Nam');
me;
// Person {name: "Nam"}
// name: "Nam"
// __proto__: Object
Second, what happens when we call a function(constructor) using the keyword 'new'?
1) clone prototype to create a new object
2) Add property and method
3) Return new object(And it is called 'instance')
var me = (function(name) {
var instance = {}; // creates new object
instance.__proto__ = Person.prototype; // clone prototype of Person and delegates it
instance.name = name; // add property
return instance; // return instance
})('Nam'); // execute this function immediately
me;
// Person {name: "Nam"}
// name: "Nam"
// __proto__: Object
me.walk(); // Nam walks
Third, what if call a function without the keyword 'new'?
var me = Person('Nam');
me; // undefined
window.Nam; // 'Nam'
Since we do not call the constructor, an instance is not returned so the variable 'me' is undefined.
Furthermore, the parameter 'Nam' is bound to the global scope object 'window'.
It is because of the keyword 'this' and we will see more details later.
Just let us focus on what the constructor does.
3. Appendix
As I mentioned before, the Function is an Object.
Let's see what happens when we define a function.
First. Let's see the below UML :
- Red Lines point '__proto__'
- Blue Lines describe the relationship between constructor and prototype
Function 'Person' inherits object 'Function.prototype' using the prototype chain.
So function 'Person' can use all properties and methods of 'Function.prototype'.
For example, there is a property 'argument' and it returns the parameter of a function in Array type.
It works in all kinds of functions even though we do not define it.
How is it possible?
Because it is the property of 'Function.prototype', so all functions inherit it using a prototype chain.
Second, look at the above UML closely.
There is one strange thing.
Actually, I painted an object 'orange' and function 'blue'.
I told that 'prototype' is working 'object' instance.
But look at the image again.
I painted 'Function.prototype' blue.
Did I make a mistake?
typeof Object.prototype; // "object"
typeof Array.prototype; // "object"
typeof Person.prototype; // "object"
// Only Function.prototype is different
typeof Function.prototype; // "Function"
It seems this result is a contradiction, but it is not.
I quote ECMAScript 2015:
The Function prototype object is the intrinsic object 'Function Prototype'.
The Function prototype object is itself a built-in function object.
Consequently, 'typeof Function.prototype' returns "Function" but it is 'built-in' object.
If 'Function.prototype' was a real function, it should have to contain the property 'prototype'.
Function.prototype.prototype; // undefined
But it is not.
Third. 'Object.prototype'
This is full version of the object model.
As you can see, all prototypes head to 'Object.prototype'.
'Object.prototype' is the top-level of all objects.
In other words, there is no object behind 'Object.prototype'.
Object.prototype.__proto__; // null