Detailed explanation of var, let, const characteristics and differences in JavaScript

1. Disadvantages of var declaration variables in ES5

ES5 actually provides us with two methods of declaring variables: var command and function command.
Using the function command to declare a function is not involved in the discussion here, we mainly compare the var command.

The var command declares variables with three characteristics:

  • Variables can be declared repeatedly;
  • Variable declarations will be promoted;
  • No block-level scope;

These three characteristics make the writing of JS code seem a bit "random" and not standardized enough, and such grammatical logic is also counterintuitive. Give two examples:

1.1 The inner variable will cover the outer variable
with the same name. We use var to declare a global variable num and assign the value to 1, and then redeclare the num variable in the if code block in the scope of the show function and assign it to 2

var num = 1;

function show() {
    
    
  console.log(num);
  if (false) {
    
    
    var num = 2;
  }
}

show(); // undefined

The final output result of show function execution is undefined.
This is because the variable declared by var has no block-level scope. The second redeclared num will be promoted to the beginning of the function, covering the outer global variable with the same name. At this time, the output result must be undefined.

1.2 The loop variables used for counting in various loop structures will be leaked as global variables.
When the loop structure is used, a loop control variable (such as i, j, k, etc.) will be declared, but it does not disappear after the loop ends. Leaked into a global variable.

for (var i = 0; i < 3; i++) {
    
    
  //...
}
console.log(i); // 3

A better approach is that we want it to be valid only in the loop control, and it will automatically fail after the loop ends, and will not affect the execution of other parts of the code. At this time, we need to use the new let in ES6.

2. Let and const basics

2.1 Basic usage of
let The let command is a new command used to declare variables in the ES6 standard.
Its mission is to replace the var command. Its usage is similar to var, but it makes up for var's design flaws.
Difference: The let command can declare the current code block as a block-level scope, and the variables declared with the let command are only valid in the current code block. (The code block takes a pair of curly braces {} as the unit)

{
    
    
  let a = 1;
  var b = 2;
}

console.log(a) // ReferenceError: a is not defined.
console.log(b) // 2

Accessing variable a outside the code block will report an undefined error, while the variable b defined by var can still be accessed.

Now with the let command, you can solve the second problem at the beginning of this article: the problem of loop variable leakage.
We use let to declare the counter i of the for loop:

for (let i = 0; i < 3; i++) {
    
    
  //...
}
console.log(i); // ReferenceError: i is not defined

The variable i cannot be accessed at this time.

❀ Expansion 1: ❀

When using the let command in a loop, there is another point to note: the variable i will be re-declared each time in the loop .

Use the loop variable i declared by var, and add a timer function in each loop to print out this loop variable i:

for(var i = 0; i < 3; i++) {
    
    
  setTimeout(function() {
    
    
    console.log(i); // 3  3  3
  }, 1000);
}

Three 3s are output because the loop variable i in the entire for loop is always the same variable, and finally the variable i is assigned the value 3 at the end of the loop.
Then change to the let command and output it again:

for(let i = 0; i < 3; i++) {
    
    
  setTimeout(function() {
    
    
    console.log(i); // 0  1  2
  }, 1000);
}

You can see that the output result is the same as without the timer function. This is because the variable i is re-declared in each loop.
It is still output according to the normal logic, because the JavaScript engine will remember the value of the previous round of loops. When the variable i of this round is initialized, calculations are performed on the basis of the previous round of loops.

❀ Expansion 2: ❀

The for loop itself has another special feature: the part that sets the loop variable is a parent scope, and the inside of the loop body is a separate child scope

for (let i = 0; i < 3; i++) {
    
    
  let i = 'zevin';
  console.log(i); // zevin  zevin  zevin
}

Zevin was output 3 times. This shows that the variable i inside the loop body and the loop variable i are not in the same scope, and have their own separate scopes.

2.2 Basic usage of const

The const command is used to declare a read-only constant. The value must be assigned at the beginning of the declaration, and once declared, it cannot be changed.

const PI;
// SyntaxError: Missing initializer in const declaration

const PI = 3.1415926;
PI = 3.14;
// TypeError: Assignment to constant variable.

❀ Expansion ❀ What the
const command actually guarantees is not that the value of the variable cannot be changed, but that the data stored in the memory address pointed to by the variable cannot be changed.

For basic types of simple data (numerical value, string, Boolean value), the memory address pointed to by the variable stores the value itself, so it is equivalent to the value of the variable that cannot be modified;

const obj = {
    
    };

// 可以添加属性
obj.name = 'zevin';
console.log(obj.name);
// zevin

// 让obj指向另一个对象就会报错
foo = {
    
    }; 
// TypeError: "obj" is read-only

For reference data types (mainly arrays, objects), the memory address pointed to by the variable saves the reference address, but the reference address cannot be changed. For the array, the object itself, we can still add or delete element.

3. ES6 New Specification for Variable Declaration

In order to improve the declaration status of the var command in ES5, and also to improve the standardization of the JS language, the following four new variable declaration specifications are proposed in ES6, and both let and const commands are applicable.

3.1 Block-level scope
ES5 has only global scope and function scope. Finally, a new block-level scope is added to ES6. Variables declared using let or const commands are only valid in the block-level scope where they are declared.

{
    
    
  let a = 1;
  if(true){
    
    
    const a = 2;
  };
  console.log(a); // 1
}

The code block takes a pair of curly braces {} as the unit, which can be nested arbitrarily without affecting each other.

{
    
    {
    
    {
    
    {
    
    
  {
    
     const age = 12 }
  console.log(age); // age is not defined
}}}};

The above code uses a five-level block-level scope, each of which is a separate scope.
The fourth-level scope cannot read the internal variables of the fifth-level scope.

3.2 There is no variable promotion
The variable declared by the var command will be promoted to the beginning of the document or the beginning of the function, that is, the variable can be used before the declaration, and the value is undefined,
and this syntax behavior is fixed in ES6, which is declared by the let and const commands Variables must be used after declaration, otherwise an error will be reported.

console.log(a); // undefined 
console.log(b); // ReferenceError: Cannot access 'b' before initialization
console.log(c); // ReferenceError: Cannot access 'c' before initialization

var a = 1;
let b = 2;
const c = 3;

3.3 Temporary Dead Zone
ES6 clearly stipulates that if there are let and const commands in a block, the variables declared by these commands in this block will form a closed scope from the beginning.
If these variables are used before the declaration, an error will be reported. This is grammatically called "temporal dead zone" (TDZ for short).

if (true) {
    
    
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

In the above code, before the let command declares the variable tmp, all belong to the "dead zone" of the variable tmp.

❀ Expansion❀

The emergence of "temporary dead zone" also means that typeof is no longer an error-free operation.

console.log(typeof a); // undefined
console.log(typeof b); // ReferenceError
const b = 1;

Before the variable b is declared with const, it belongs to the "dead zone" of the variable b. As long as the variable is used, an error will be reported. Therefore, the typeof operator will throw a ReferenceError.
But if a variable is not declared at all (variable a), using typeof will not report an error, but undefined.

3.4 Repeated declarations
are not allowed In ES6, repeated declarations of the same variable are not allowed in the same block scope.

if(true){
    
    
  var a = 1;
  let a = 2;
  const a = 3;
}
// SyntaxError: Identifier 'a' has already been declared

So in the same way, let or const commands cannot be used in a function to redefine a variable with the same name as a formal parameter, but var can.

function func(num) {
    
    
  let num = 1;
  console.log(num);
}
func() // SyntaxError: Identifier 'num' has already been declared
function func(num) {
    
    
  var num = 1;
  console.log(num);
}
func() // 1

Since different block-level scopes do not affect each other, we can define variables with the same name in different block-level scopes.
So the following code will not report an error:

function func(num) {
    
    
  var num = 1;
  if(false){
    
    
    let num = 2;
    console.log(num); // 2
  }else{
    
    
    const num = 3;
    console.log(num); // 3
  }
  console.log(num); // 1
}
func()

Guess you like

Origin blog.csdn.net/ZYS10000/article/details/113698838