0 Previously on
Recently, I met the following question in the interview:
// q: What is the output of console.log below?
var arrowFunction = () = > {};
console.log(new arrowFunction());
Copy the code
At that time, I thought that the arrow function was a special function that declared scope. Therefore, I answered {} according to the idea that the function entity returned no specific value, but returned an empty object. The result was not correct.
So this raises a lot of questions:
-
Why does the new arrow function report an error?
-
What is the actual execution logic of new?
-
What is the relationship between arrow functions and ordinary functions?
-
How do I interpret the call method of the arrow function?
-
How is the arrow function implemented in Polyfill?
1. Old cognition and practice
Arrow functions are not bound by default to variables such as this and arguments, so I use the normal function instantiation steps I learned in the past: Take the following code as an example
var functionConstructor = function() {
this.a = 'normal word';
};
new functionConstructor('prop word);
Copy the code
1. Create empty object tar = {}; 2.tar.__proty__ = functionConstructor.prototype 3. Create res = functionconstructor.call (tar, arguments) 4. If res is an object and not null, return res, otherwise return tar. The arrow function should return tar, {}.Copy the code
(No wonder the interviewer asked a bunch of function-related questions later).Copy the code
2. Go back to the source
Since we can’t keep up with the cognition, instead of learning as before, let’s go back to the source and solve the problem from the ES specification.
ps: ECMAScript@2020 Language Specification
Ps2: There are a lot of provisions in the specification. This paper only expounds the parts related to the problem.
2.1 ES specification — Arrow functions and ordinary functions
Let’s first look at the runtime evaluation of the arrow function (14.2.17) :
Here is the run-time evaluation of a normal function (14.1.24) :
The main differences are as follows:
-
The fourth argument, ThisMode, differs between the two method calls ·OrinaryFunctionCreate·, and semantise-this ends up letting the runtime environment not bind this (and its internal checks, etc.) or create arguments references.
-
Normal functions call the ·MakeConstructor· method at step 3, but arrow functions do not. This method injects a Consturct attribute (important) into the function.
Official tip for arrow function:
Arrow functions do not bind arguments, super, this, or new.target by default (new refers to the function itself and the arrow function will declare new.target as invalid in that language), but super may have bindings.
Ps: I have to dig a hole here, I have to understand the environmental claims of the set of rules to read this.
2.2 Bonus — Arrow functions with Call
As mentioned above, the arrow function modifies ThisMode = lexical, and by the call specification, the original this is not modified in the call chain, so calling call and calling call end up being the same.
Um participant:
function someClass () {
this.variable = 'inside variable';
return () = > {console.log(this.variable)};
}
someClass.call({})(); // inside variable
someClass.call({}).call({variable: 'outside variable'}); // inside variable
Copy the code
2.3 ES specification — new keyword
The logic of the new keyword is extremely simple.
Execute new logic (12.3.5.1.1) :
After the checksum arguments are prepared, step 7 checks that the given constructor is a constructor with IsConstructor (7.2.4) and raises TypeError if it is not.
Test Construct if the value is an object and the package contains no methods inside Construct:
We know from the previous comparison that the arrow function does not run MakeConstructor during execution, so there is no Construct internal method, so the standard IsConstructor returns false directly and TypeError is raised by the new keyword execution.
The results are slightly different when Chrome is running:
Chrome probably threw an error in the IsConstructor method.
2.4 Bonus — Other methods in which new will throw an exception
[
async function() {},
Function.prototype,
// Global objects without Construct: Atomics, JSON, Math, Reflect
Math.JSON.Reflect,
Atomics,
// Proxy for objects without the Construct attribute
].map(e= > {
try{
new e();
} catch(err) {
console.error('can`t use new with:', e, 'error msg:', err); }})Copy the code
3 Polyfill implementation
babel => ie 10
4 summary
Maybe this is to review the old to learn new bar (mistake), but can learn new things is good, the more digging more feel that they only know the surface; At the same time, I also gave myself a new pit about the execution environment. I tried this for a period of time, and found that I had to integrate many pieces of content to see together (a lesson from the previous car).
Note: this is my first article, there may be bugs, if you need to supplement or erratum the content, please leave a message or private message, I will regularly check and repair.