Leaving all the positive or negative comments behind, it’s absolutely crucial to understand how it totally works.
Here are some of the points that are hard to discover:
Before starting the journey, please take into consideration that along this writing
- function and Function, as well as object and Object refer to different things.
- function object is an object whose type is function
Here are some critical observations:
- Function, is the only function whose __proto__ accessor property and prototype data property points to the same object: Function.prototype
- So we can say that Function is the only function who gives birth to itself. (Function can be said to be indirectly the constructor of itself)
- Proof: Function.prototype.constructor refers to Function.prototype object.
console.log(Function.prototype.constructor == Function) // true
console.log(Function.__proto__ == Function.prototype) // true
console.log(Function.__proto__.constructor == Function) // true
- Function.prototype object is what makes all functions special (call and apply resides in Function.prototype)
- All other functions in our code, are created through the constructor call to Function (new Function(.. , .. ))
- All other functions that are created through the new Function(), returns
- Function.prototype object through the __proto__ accessor property
- A newly created functionName.prototype object through the prototype data accessor
Let’s see this
- When the compiler comes across a function declaration (case 1) or a function expression (case 2), it makes a constructor call to Function. (new Function(.. , ..))
- That constructor call returns a new object instance. (that’s what new operator always does)
- That object instance (which is a function object) (hereafter, let’s call this function object Y) is attached into its lexical scope forever. Hence, this function object (Y) will always be able to reach to its parent scope. However, the parent scope does not yet know about the existence of this function object.
- If it was a function declaration (case 1), a new variable (which equals to the function’s name) is created on the parent scope and the reference of the newly created function object (Y) is assigned into the variable.
- If it was a function expression (case 2), this expression returns the reference of the newly created function object (Y). (hence can be stored in a variable, be passed as an argument (callback) or returned (higher order function))
- Now, because the function object (Y)resides where the statement or declaration exists, only the reference of this object (Y) can be moved around. So even if you think you are passing a function value as an argument or that you think you are returning a function value, what is actually happening is that a function object is created right there, but only the reference of this object is passed or returned. That’s why closure work. You always call the function where it is expressed or declared; hence the function always lookup the same scope.
- The other thing that the constructor call (new Function(.. , .. )) does is that it assigns Function.prototype into the newly created function object’s (Y’s) internal [[prototype]] (through the setter on Object.prototype.) Hereafter, if you access __proto__ on this newly created function object (Y), it will return Function.prototype
- The last thing that happens: a new object is created: Y.prototype
- Y.prototype has a single property: constructor
- Y.prototype.constructor refers Y
- Because all the functions in our code are constructed by Function, all those functions’ __proto__ accessor property points to Function.prototype
console.log(Y.__proto__.constructor === Function); // true
console.log(Y.__proto__ == Function.prototype); // true
- Now we have a variable Y which points to a function object that is constructed by Function.
- If we call Y by new operator (constructor call)
- A new object (foo) (of type object) is created.
- It’s __proto__ is set to Y.prototype
- foo.__proto__.constructor points to Y
var foo = new Y();
console.log(foo.__proto__ == Y.prototype) // true
console.log(foo.__proto__.constructor == Y) // true
Likewise, let’s examine what Object function does
When we make a constructor call to Object (new Object())
- A new object is created (bar)
- It’s __proto__ accessor property refers to Object.prototype
I also run a coding bootcamp: https://www.yenikodyazilimkursu.com