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 nameAt the back of thenameIf 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 reportedReferenceErrorError because the value of the variable name or function name has been initialized toundefined.
  • Check out JavaScript you Don’t knowGitHubOn the warehouseissueIs 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