Lift the reactorin JavaScript
1. Concepts of declaration, assignment, and promotion
1.1 the statement declaration
Without considering ES6, there are two kinds of statements:
- Variable declarations
var a
- Function declaration
function f() {}
Note that the function declaration uses the function keyword. It is a whole, containing the name, arguments, and body of the function. It cannot be broken down into declaring a variable and then assigning a function to that variable.
- A code
// Declare function f using function
function f() {
console.log('hello')}Copy the code
- Code 2
// 1. Declare f
var f
// 2. Assign a function to the variable f
f = function() {
console.log('hello')}Copy the code
The above two pieces of code, while identical when called, are not equivalent when considering the promotion problem! The code segment 2 is actually the unbundled form of the function expression, that is, the function declaration is not unbundled for execution by the engine, and the function expression is unbundled for two-step execution by the engine, as described in the next section.
1.2 the assignment of the assignment
Declarations and assignments are often written in a single statement, but they need to be treated separately. Specifically, the engine executes declarations at compile time, leaving assignment operations in place and executing them at execute time. Two scenarios are also considered here:
- General variable declaration and assignment
- Declaration and assignment of function expressions
1.2.1 Declaration and assignment of general variables
For example, we have the following statement:
var a = 666
This looks like a statement, but the engine actually breaks it down into declaration and assignment:
- Statement:
var a
The engine will perform this step in advance of the compilation phase.
- Assignment:
a = 666
This step is left in place by the engine during the Execution phase.
1.2.2 Declaration and assignment of function expressions
Similarly, the function expression var f = function() {} is broken down into declaration and assignment steps:
- Statement:
var f
Execute ahead of time at compile time
- Assignment:
f = function() {}
Stay where you are and execute in the execution phase
As you can see, the declaration and assignment process for function expressions is very similar to that for general variables.
1.3 improve hoisting
Now that we can distinguish between declarations and assignments, and know that they are executed in different stages placed by the engine, what is promotion?
The engine separates declarations from assignments or other executable logic, where declarations are executed earlier at compile time, while assignments or other executable logic are left in place and executed at execution time. This behavior of the engine looks like an upgrade to us.
Elevate the following: Variable and function declarations are moved from their original position to the top of the scope, leaving assignments or other executable logic in place.
1.4 Common Misunderstandings
A boost is actually a “look” effect and does not mean that the part of the code that declares it has actually moved. Here is a quote from MDN:
Developer.mozilla.org/en-US/docs/… the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
In other words, the declarations of variables and functions are simply put in memory during compilation, and the code remains where it was. It has not been moved. It is just an equivalent way to understand how the engine handles things.
2. Improve detailed explanation
2.1 Classifications of promotion and their equivalent forms
There are two kinds of ascension
- Promotion of a variable or function expression
As described in Section 1.2.2, the declaration and assignment of function expressions are very similar to that of general variables, so promotion of function expressions is similar to promotion of variables.
- Promotion of function
The function here does not include function expressions.
2.1.1 Promotion of variable or function expression
Uplift of variables
var a = Awesome!
Copy the code
Equivalent form:
var a
Copy the code
a = Awesome!
Copy the code
Note: In order to reflect the compilation phase and the execution phase, I have divided the code that should be in one paragraph into two paragraphs, which will not be repeated later.
Promotion of function expressions
var f = function() {
console.log('hello')}Copy the code
Equivalent form:
var f
Copy the code
f = function() {
console.log('hello')}Copy the code
2.1.2 Function promotion
function f() {
console.log('hello')}Copy the code
Equivalent form:
// Compile phase
function f() {
console.log('hello')}Copy the code
// Run phase
Copy the code
As you can see, function promotion does not break down into a function expression, declaring a variable and then assigning a function to that variable.
2.2 Improvement Examples
2.2.1 Variable promotion
Consider this code:
console.log(a)
var a = Awesome!
// undefined
Copy the code
All of the results of this article are the results of node.js. Some of the results will be different than in the browser, but it doesn’t matter.
The reason why undefined is printed here instead of ReferenceError is because var a was executed in the compile phase by the engine, which means that the variable is being promoted. It corresponds to the following code.
var a
Copy the code
console.log(a)
a = Awesome!
// undefined
Copy the code
2.2.2 Function expression promotion
Consider the following code:
f() // TypeError
var f = function() {
console.log(Awesome!)}Copy the code
The above code causes an error because function expressions are like general variables, and the engine breaks them into declaration and assignment steps. The declaration is executed ahead of time at compile time, while the assignment is left in place and executed in execution time.
Note: The error is a TypeError, not a ReferenceError, because f is declared as a variable by var f at compile time, so the engine can find the name f and will not report the ReferenceError. However, when f() is executed, the value of f is still undefined, equivalent to executing undefined(), so TypeError is reported.
The above code, promoted, is equivalent to:
var f // The function expression is promoted
Copy the code
f() // TypeError
f = function() {
consoel.log(Awesome!)}Copy the code
For a named function expression, its name identifier is also not available in the scope before assignment:
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {
// ...
};
Copy the code
The above code corresponds to the following form:
var foo;
Copy the code
foo(); // TypeError
bar(); // ReferenceError
foo = function() {
varbar = ... self...// ...
}
Copy the code
2.2.3 Function promotion
Consider this code:
f() // hello
function f() {
console.log('hello')}Copy the code
The above code, promoted, is equivalent to:
function f() {
console.log('hello')}Copy the code
f() // hello
Copy the code
Because of function promotion, calling a function first and then defining it does not cause an error, which is not possible in some programming languages.
2.3 Repeated statements are ignored by the engine
Consider the following code:
var a = Awesome!
var a
console.log(a)
/ / 666
Copy the code
According to ascension theory, the above code should be equivalent to the following:
var a // var a = 666
var a // Repeated declarations are ignored by the engine
Copy the code
a = Awesome!
console.log(a)
/ / 666
Copy the code
You can see that the repeated declaration does not reinitialize the variable a to undefined, but is ignored.
As long asvar name
At the back of thename
If it already exists, whether it is a variable or a function, the engine will ignore repeated declarations for it.
Keep in mind that repeated declarations are ignored by the engine, which will be used in the next section.
2.4 Promotion of functions and variables or function expressions of the same name
Conclusion: If a function and a variable (or function expression) of the same name are present, the function is promoted first, the variable (or function expression) second.
2.4.1 Functions and variables of the same name
Consider this code:
function f() {}
var f
console.log(f)
// [Function: f]
Copy the code
After promotion is equivalent to:
function f() {}
var f // A duplicate declaration of an existing name f is ignored by the engine
Copy the code
console.log(f)
// [Function: f]
Copy the code
Try switching the order:
var f
function f() {}
console.log(f)
// [Function: f]
Copy the code
[Function: f] [Function: f]
function f() {} // Function declarations are promoted first
var f // Repeated declarations are ignored
Copy the code
console.log(f)
// [Function: f]
Copy the code
2.4.2 Functions and Function Expressions with the same name
The case of a function expression is similar to that of a general variable declaration assignment. Consider this code:
function f() {
console.log(1)}var f = function() {
console.log(2)
}
f()
/ / 2
Copy the code
After promotion is equivalent to:
function f() { // Function declarations are promoted first
console.log(1)}var f // Repeated declarations are ignored
Copy the code
f = function() {
console.log(2)
}
f()
/ / 2
Copy the code
Try switching the function expression and the function declaration:
var f = function() {
console.log(2)}function f() {
console.log(1)
}
f()
/ / 2
Copy the code
After promotion is equivalent to:
function f() { // Function declarations are promoted first
console.log(1)}var f // Repeated declarations are ignored
Copy the code
f = function() {
console.log(2)
}
f()
/ / 2
Copy the code
Add another function call before it and see what happens:
f() / / 1
function f() {
console.log(1)}var f = function() {
console.log(2)
}
f() / / 2
Copy the code
After promotion is equivalent to:
function f() { // Function declarations are promoted first
console.log(1)}var f // Repeated declarations are ignored
Copy the code
f() / / 1
f = function() {
console.log(2)
}
f() / / 2
Copy the code
Switch the order and see if there is any change:
f() / / 1
var f = function() {
console.log(2)}function f() {
console.log(1)
}
f() / / 2
Copy the code
The output is unchanged, and the above code is upgraded to the equivalent of:
function f() { // Function declarations are promoted first
console.log(1)}var f // Repeated declarations are ignored
Copy the code
f() / / 1
f = function() {
console.log(2)
}
f() / / 2
Copy the code
2.4.3 Functions, variables, and function expressions with the same name
If a function, variable, or function expression has the same name, the variable declaration will be promoted first, and then the variable and function expression declarations will be promoted in the same order. Of course, repeated declarations will be ignored, but the following declarations and assignments will override the preceding declarations and assignments.
f() / / 4
function f() {
console.log(1)}var f = function() {
console.log(2)}var f = 3
function f() {
console.log(4)
}
f() // TypeError
Copy the code
The above code, promoted, is equivalent to:
function f() { // Function declarations are promoted first
console.log(1)}function f() { // The following declaration overrides the previous one
console.log(4)}var f // Repeated declarations from function expressions are ignored
var f // Repeated declarations from variables are ignored
Copy the code
f() / / 4
f = function() {
console.log(2)
}
f = 3 // Where f is assigned to a number
f() // TypeError
Copy the code
2.5 Promotion occurs in the current scope
This is a bad question, and I haven’t come to a firm conclusion, but here’s a tentative opinion.
- In some browsers, promotion ignores block-level scope and occurs in the current function scope. This is what JavaScript you Don’t Know says, and the book also says not to rely too heavily on this feature because it can change at any time.
- In other browsers, the workflow of the promotion is less clear. To be sure, if a variable or function name is used outside the scope of the current block and before the promotion, it will not be reported
ReferenceError
Error because the value of the variable name or function name has been initialized toundefined
. - Check out JavaScript you Don’t know
GitHub
On the warehouseissue
Is still an unresolved state.
Consider the following code:
f()
if (true) {
function f() {
console.log('hello')}}else {
function f() {
console.log('world')}}Copy the code
In some browsers (I don’t know which ones), the upgrade is equivalent to:
function f() {
console.log('hello')}function f() {
console.log('world')}Copy the code
f() // world
if (true) {}else{}Copy the code
So output world.
Other browsers, such as Firefox Quantum 69.0.1 and Chrome 76.0.3809.132, will report TypeError. Note that it is not ReferenceError. Because f is undefined at the beginning, which is weird.
Even more difficult for me to understand is the following code:
console.log(a) // undefined
{
console.log(a) // function a()
function a() {}
a = 50
console.log(a) / / 50
}
console.log(a) // function a()
console.log(b) // undefined
{
console.log(b) // function b()
b = 50
function b() {}
console.log(b) / / 50
}
console.log(b) / / 50
Copy the code
If a = 50 and b = 50 are added before var, SyntaxError: Identifier has already been declared. If any friend knows what happened, please let me know, thank you!
2.6 Do not declare that direct assignments do not promote
Assigning a value to a variable without a declaration will not be promoted and will be left in place by the engine.
2.6.1 Assign a variable without declaring it directly
console.log(a) // ReferenceError: a is not defined
a = Awesome!
Copy the code
The ReferenceError does not raise a = 666, nor does it implicitly raise var a.
2.6.2 Assigning a function without declaring it
console.log(f) // ReferenceError: f is not defined
f = function() {
console.log('hello')}Copy the code
The ReferenceError is reported, indicating that the f function declaration is not promoted.
2.7 Promotion after return
Statements following return are not executed, but if there are variable declarations and function declarations, the declaration part is promoted, assignment, and the rest of the executable logic are left in place.
2.7.1 Variable declaration after return is promoted
Consider this code:
var num = 2
function f() {
num = 1
console.log(num) / / 1
return
var num = 3
}
f()
console.log(num) / / 2
Copy the code
Is equivalent to:
var num
num = 2
function f() {
var num // var num = 3
num = 1 // In this case, num is a local variable
console.log(num) / / 1
return
num = 3
}
f()
console.log(num) / / 2
Copy the code
2.7.2 Function declaration after return is promoted
Consider the following code:
var a = 1
function b() {
a = 10
return
function a(){
console.log(a)
}
}
b()
console.log(a) / / 1
Copy the code
After promotion is equivalent to:
var a = 1
function b() {
a = 10
return
function a(){
console.log(a)
}
}
b()
console.log(a) / / 1
var a
function b() {
function a() { // The function declaration is promoted to the current scope
console.log(a)
}
a = 10 // The local scope of a is covered with 10
return
}
a = 1
b()
console.log(a) // Print the global scope of a
Copy the code
3. References
- JavaScript preparse: the same name variable and function, the same name function expression and the same name function declaration, which and the variable promotion pit
- Js variable name and function name the same problem
- You Dont’t Know JS