Var, let, and const are the three ways in which JavaScript can declare variables. Let and const are the two new ways in which ES6 has added variables to JavaScript. Their usage is similar to var. When asked about the difference between them, one of the answers is that there is no variable promotion for let and const. But after some research, it was found that this answer is not so accurate.
1. Variable improvement
The var command is known to promote variables, which can be used before the declaration:
console.log(a); // undefined
var a = 1;
Copy the code
This is odd because, according to normal logic, variables should be used after the statement is declared. In fact, JavaScript, like any other language, goes through a compile and execution phase. However, the JavaScript compiler collects all variable declarations during compilation and moves them to the top of the scope where the variable is currently located. In other words, variable declarations are executed during compilation, while assignments are executed during execution. Hence the so-called “variable enhancement”. The above code is equivalent to:
var a;
console.log(a); // undefined
a = 1;
Copy the code
Why stress the present? Because ES5 is divided into global scopes and function scopes, variables with the same name in different scopes do not affect each other. Such as:
console.log(b); // ReferenceError: b is not defined
function foo () {
console.log(b); // undefined
var b = 1;
}
foo()
Copy the code
When the code executes, the variable b in the scope of the function is promoted to the top of the current scope, that is, the top of the function foo, not the top of the overall code, so undefined is printed inside the function, and there is no variable b outside the function, so the ReferenceError is reported.
Implicit global variables are not promoted:
function foo () {
console.log(b) // ReferenceError
b = 1
console.log(b) / / 1
}
foo()
console.log(b) / / 1
Copy the code
Use the var statement variables, is a local variable within the function, on the outside of the function is a global variable, don’t use the var statement variables, the functions are global variables, internal or external but if it’s declared within a function, also called implicit global variables, on the outside of the function need to call first before using method, told system behind the statement the global variable can be used on the outside of the function.
In addition, function declarations are also promoted:
foo(); / / 1
function foo () {
console.log(1)}Copy the code
The above code is equivalent to:
function foo () {
console.log(1)
}
foo(); / / 1
Copy the code
Function expressions are not promoted
foo(); // TypeError: foo is not a function
var foo = function () {
console.log(1)}Copy the code
This is because the JavaScript compiler reads the code declared by the function first during compilation to ensure that the function can be referenced. For function expressions, parsing is done only when the corresponding statement is executed. In other words, the code declares a variable foo and assigns the function to it. The variable promotion originally said that the declaration of the variable was promoted to the top, and the assignment code was left where it was, so the function expression would not be promoted. Is equivalent to:
var foo;
foo();
foo = function () {
console.log(1)}Copy the code
This also explains why function promotion takes precedence over variable promotion, right
console.log(foo); // [Function: foo]
var foo = 10;
function foo () {}
Copy the code
The above code is equivalent to:
function foo () {}
var foo;
console.log(foo);
foo = 10;
Copy the code
Why aren’t functions and variables of the same name covered?
This is because Javascript uses the ignore rule for variable declarations with the same name, and later declarations are ignored. For function declarations with the same name, Javascript uses the override rule. The first declaration is overridden. For function declarations and variable declarations with the same name, the rule is ignored. In order to ensure that the function can be referred to, the function declaration is promoted before the variable declaration, and the variable declaration is ignored, but the variable is overridden after assignment.
Variables of the same name:
/ / before parsing
var a = 1;
var a =2;
/ / resolved
var a;
var a; / / is ignored
a = 1;
a = 2;
Copy the code
Function of the same name:
function foo () {
console.log(1)}function foo () { // Override the previous one
console.log(2)
}
foo(); / / 2
Copy the code
Functions and variables of the same name:
/ / before parsing
console.log(foo); // [Function: foo]
var foo = 10;
function foo () {}
console.log(foo); / / 10
/ / resolved
function foo () {}
var foo; / / is ignored
console.log(foo);
foo = 10;
console.log(foo); / / 10
Copy the code
2. Let and const
In ES6, let and const have changed their syntax behavior to correct the “variable enhancement” phenomenon. Variables declared by let and const must be used after the declaration, otherwise an error will be reported:
console.log(a); // ReferenceError
let a = 1;
Copy the code
In addition, let and const actually add the concept of block-level scope to JavaScript. Variables declared by let or const are valid only within the block of code in which the command resides.
let a = 1;
if (true) {
a = 2; // ReferenceError;
let a = 3;
}
Copy the code
In the above code, there is a variable a outside the if block, but the let inside the if block declares a variable a. As a result, the variable a is bound to the block-level scope and is not affected by external effects. Therefore, an error will be reported when used before the let declaration inside the if block. The inner scope is not affected by the outer scope. The outer scope cannot read variables from the inner scope. Therefore, variables with the same name can be defined in different scopes.
3. Is there a variable increment for let and const?
With the first two big concepts out of the way, let and const are not promoted. As you can see from the example in title 2, using a variable before a let is declared raises a ReferenceError. Does that mean let and const are not promoted?
In fact, let and const are promoted. Specifically, creation is promoted, but initialization is not.
According to the NOTE in 13.3.1 of ECMA-262: Let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until A variable defined by A LexicalBinding with an Initializer is assigned the Value of its Initializer’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.
Let and const define the lexical environment in which variables are executed. Variables are created when the environment is instantiated, but are not allowed to be accessed in any way until the variables are lexically bound…… If a variable declared by a let is initialized with no lexical binding, an undefined value is assigned. The MDN introduction to lets also states that var is different from a let in that the latter is initialized at compile time. (Lexical context should refer to context, and lexical bindings should refer to assignment operations.)
Let declaration variables are divided into three parts: 1. Creation; 2. Initialization, 3. Assignment. The creation process is completed when the current environment is instantiated. Once declared, the value of the constant (the memory address cannot be changed) cannot be changed, so a const declaration must be initialized immediately. It cannot be left for later assignment. Therefore, a const declaration has two parts: 1. Create, 2. Initialize, no assignment operation, in fact, the initialization of the assignment into one step, at the initialization of the assignment.
Conclusion:
According to the above mentioned 13.3.1 in ECMA-262, MDN document and title 1, when variables are declared by var, the creation and initialization of variables are promoted. Without the promotion and assignment operation, it can be understood that the variable declaration by var command is actually divided into two parts: the first part is initialized while the first part is created, and the second part is assigned. So the code in header 1 will print undefined:
// If a variable is declared via var, its creation and initialization are promoted, and its assignment is not promoted, so it is initialized to undefined
console.log(a); // undefined
var a = 1;
Copy the code
While let and const only improve variable creation, initialization and assignment are not improved
if (true) {
a = 2; // ReferenceError;
let a = 3;
}
Copy the code
For ease of understanding, the above code can be broken down into the following steps:
if (true) {
// At this point the creation of a has been promoted to the top of the if block
a = 2; // ReferenceError; A is not defined; a is not defined; a is not defined; a is not defined
letA;// Complete the initialization of a, where a is undefined according to ecMA-262
a = 3; // Complete the assignment to a.
}
Copy the code
The part of the let that is promoted from creation to initialization is known as the temporary dead zone (TDZ), which means that a variable is not available until it is initialized using the let command.
.if (true) {
// The creation of a is promoted, the beginning of TDZ
a = 2; // ReferenceError;
letA;// Complete the initialization of a, and the end of TDZ
a = 3; // Complete the assignment to a.
}
Copy the code