preface
In my previous article, I talked about variable promotion in JavaScript, which leads to a lot of unintuitive code and bugs. This is also an important design flaw in JavaScript. So the following article shows how to fix this defect by using block-level scoping with the let and const keywords.
Scope (scope)
Why does variable promotion exist in JavaScript when no other language seems to have it? To understand this, we have to start with scope.
Scope is the area in a program where a variable is defined, and this location determines its life cycle. Popularly understood, scope is the accessible scope of variables and functions, that is, the scope controls the visibility and life cycle of variables and functions.
Prior to ES6, there were only two types of scope for ES: global scope and function scope.
- Objects in the global scope are accessible anywhere in the code, and their life cycle follows the life cycle of the page.
- A function scope is a variable or function defined inside a function that can only be accessed inside the function itself. At the end of function execution, variables defined inside the function are destroyed.
Prior to ES6, JavaScript only supported these two scopes, while block-level scopes were commonly supported in other languages. Block-level scope is a piece of code wrapped in braces, such as functions, judgment statements, looping statements, and even a single {} can be considered a block-level scope.
To better understand block-level scope, you can refer to some sample code below:
// foo(){} // foo(){} // foo(){} // foo(){} i<100; I++){} // separate block {}Copy the code
Simply put, if a language supports block-level scope, variables defined inside a code block are not accessible outside the code block and are destroyed after the code in the block is executed.
ES6 did not support block-level scoping. It was the fastest and easiest design to promote variables within the scope. However, this led to variables being extracted from the execution context at compile time, no matter where they were declared. So these variables can be accessed anywhere within the entire body of the function, which is called variable promotion in JavaScript.
Problems with variable promotion
1. Variables are easy to overwrite without being noticed
The example code is as follows:
Function showName(){console.log(myname); If (0){var myname = "quietly"} console.log(myname); } showName()Copy the code
Executing the above code prints undefined instead of the “obsessed” string that we wanted. Why is the output undefined? Let’s analyze it again
After the execution context for the showName function is created, the JavaScript engine starts executing the code inside the showName function. The first implementation is:
console.log(myname);
Copy the code
To execute this code, we need to use the variable myName, and we see that there are two myName variables: one with the value “remembered” in the context of global execution; The other, in the execution context of the showName function, is undefined. JavaScript will look for the variable in the current execution context first. Because of variable promotion, the current execution context contains the variable myname, and the value is undefined, so the value of myname is undefined. So the value of myName that you get is undefined. This output is different from most other languages that support block-level scope, so it can be misleading.
2. The variable that should have been destroyed was not destroyed. Let’s look at the larger and misleading code below:
The example code is as follows:
function foo(){
for (var i = 0; i < 7; i++) {
}
console.log(i);
}
foo()
Copy the code
If you implement similar code in C or most other languages, after the for loop ends, I is destroyed, but in JavaScript code, the value of I is not destroyed, so 7 is printed. This is also due to variable promotion, which was already promoted during the creation of the execution context, so that variable I is not destroyed when the for loop ends. This is still inconsistent with the performance of other languages that support block-level scope, so it is bound to be misleading for some.
How does ES6 address the pitfalls of variable enhancement
To address the problems of variable promotion, ES6 introduced the let and const keywords, allowing JavaScript to have block-level scope like other languages.
To use let and const, you can refer to the following code:
Let x = 5 const y = 6 x = 7 const y = 9Copy the code
As you can see from this code, the difference between the two is that variables declared with the let keyword can be changed, while variables declared with const cannot be changed. However, both can generate block-level scope, and for the sake of simplicity, I use the let keyword to demonstrate this in the following code. Let’s look at a practical example of how ES6 solves this problem with block-level scoping.
Here is the code for variable promotion:
function varTest() { var x = 1; if (true) { var x = 2; // Same variable! console.log(x); // 2 } console.log(x); / / 2}Copy the code
In this code, the variable x is defined in two places. The first place is at the top of the function block, and the second place is inside the if block. Since the var scope is the entire function, only one variable x is generated, and all assignments to x within the function directly change the x value in the variable environment.
So the last output of the above code via console.log(x) is 2. For code with the same logic, the last output of the other language should be 1, because the declaration inside the if block should not affect the variables outside the block.
Since the execution logic of code that supports and does not support block-level scope is different, let’s modify the above code to support block-level scope.
The transformation process is actually very simple, just need to replace var keyword with let keyword, after the transformation of the code is as follows:
function letTest() { let x = 1; if (true) { let x = 2; // Different variables console.log(x); // 2 } console.log(x); / / 1}Copy the code
When this code is executed, the output is exactly what we expect. This is because the let keyword is block-scoped, so the JavaScript engine does not store variables declared by a let in an if block into the variable environment during compilation. This means that keywords declared by a let in an if block are not promoted to full function visibility. So the value printed out inside the if block is 2, and the value printed out outside the block is 1. This is very much in line with our programming conventions: variables declared inside a scoped block do not affect variables outside the block.
conclusion
Because JavaScript’s variable promotion has design flaws such as variable override and variable contamination, ES6 introduces block-level scoped keywords to address these issues. Var, let, const
- Var defines a variable that has no concept of blocks and can be accessed across blocks, but not across functions.
- Let defines variables that can only be accessed within the scope of a block, not across blocks or functions.
- Const is used to define a constant, must be initialized (that is, must be assigned), can only be accessed in the block scope, and cannot be modified. The same variable can only be declared in one way, otherwise an error will be reported