var, let, const variable promotion temporary dead zone

1. var, let, const

They are three ways to declare variables in JavaScript, among which let and const are two new ways for JavaScript in ES6.

There are three parts to declaring variables with var and let: 1. Creation, 2. Initialization to undefined, and 3. Assignment.

What const declares is a constant. Once declared, the value of the constant (the memory address cannot be changed) cannot be changed, so the const declaration must be initialized immediately and cannot be left for later assignment, so the const declared variable is divided into two parts: 1. Creation, 2. Initialization, there is no assignment operation, which is equivalent to integrating the initialization assignment into one step, and assigning the value during initialization.

  • The “creation” process of let and const is promoted, but the initialization is not.
  • Both “creation” and “initialization” of var have been promoted.
  • The “creation”, “initialization” and “assignment” of function have been improved. If a function declaration has the same name as a var declaration, only the function declaration is promoted and the var declaration is ignored.
  • A var declaration is global scope or function scope, while let and const are block scope.
  • A var variable can be updated and redeclared within its scope; a let variable can be updated but not redeclared; a const variable can neither be updated nor redeclared (const is used to declare constants).

Global variables without var declaration
Without var, the declared variables are global variables no matter what scope they are in. No variable promotion.
But unlike global variables declared with var, global variables declared without var can be deleted using the delete keyword.

delete is used to delete the attributes of an object. If it is a non-configurable attribute, it returns false, and in other cases, it returns true
var a = 123;
b = 456;
console.log(window.a); // 123
console.log(window.b); // 456
console.log(delete a); // false
console.log(delete b); // true
console.log(window.a); // 123
console.log(window.b); // undefined
It can be seen that variables a and b are both global variables and one of the attributes of the window object, but a cannot be deleted and b can be deleted.
Note: Do not use var to declare a variable: it does not declare a global variable, but creates a property of the global object.

Even so, it may still be difficult for you to understand the difference between “variable declaration” and “creating object properties” here. In fact, Javascript variable declarations, creation properties, and every property in every Javascript have certain flags to describe their properties – such as read-only (ReadOnly), non-enumerable (DontEnum), non-deletable (DontDelete) )etc.

Since the variable declaration has its own non-deletable attributes, such as var num = 1 and num =1, the former is a variable declaration with non-deletable attributes, so it cannot be deleted; the latter is an attribute of the global variable, so it can be deleted from the global variable. .
—————-
Copyright statement: This article is an original article by CSDN blogger “The Internet is really dangerous!!” and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this statement when reprinting.
Original link: https://blog.csdn.net/weixin_55846296/article/details/126604513

2. Variable promotion

Variable promotion

In layman’s terms, variable promotion refers to the behavior of the JavaScript engine to promote the declaration part of variables and the declaration part of functions to the beginning of the code during the execution of JavaScript code.
The JavaScript compiler will collect all variable declarations during the compilation phase and advance the variable declaration to the top of the current scope of the variable. That is to say, the variable declaration has been executed during the compilation phase, and the assignment will be executed when the corresponding statement is reached during the execution phase. will be executed. That’s why the so-called “variable promotion” appears.

console.log(a); // undefined
var a = 1;

//Equivalent to ==

var a;
console.log(a); // undefined
a = 1;
------------------------------------------

console.log(b); // ReferenceError: b is not defined
function foo () {<!-- -->
    console.log(b); // undefined
    var b = 1;
}
foo()

//Equivalent to ==

console.log(b); // ReferenceError: b is not defined
function foo () {<!-- -->
var b;
    console.log(b); // undefined
    b = 1;
}
foo()

Function promotion

There are two forms of declaration of named functions in JavaScript:

//Function declaration:
function foo () {<!-- -->}
//Variable form declaration:
var fn = function () {<!-- -->}

When a function is declared in the form of a variable, there will be a promotion phenomenon like ordinary variables, but the function declaration will be promoted to the front of the scope, and the declaration content will be promoted to the top. as follows:

fn()
var fn = function () {<!-- -->
 console.log(1)
}
// Output result: Uncaught TypeError: fn is not a function

foo()
function foo () {<!-- -->
 console.log(2)
}
// Output result: 2

Function promotion takes precedence over variable promotion

console.log(foo); // [Function: foo]
var foo = 10;
function foo () {<!-- -->}

//Equivalent to ==

function foo () {<!-- -->}
var foo;
console.log(foo);
foo = 10;

Functions and variables with the same name

For variable declarations with the same name, Javascript adopts the ignore principle, and those declared later will be ignored. For function declarations with the same name, Javascript adopts the overwriting principle, and the one declared first will be overwritten. For function declarations and variable declarations with the same name, the ignore principle is adopted. In order to ensure that the function can be referenced, the function declaration will be promoted to before the variable declaration during promotion. The variable declaration will be ignored, but the variable assignment will be overwritten later.

/**Variable with the same name**/
var a = 1;
var a =2;
// Equivalent to ==
var a;
var a; // ignored
a = 1;
a = 2;
/**Function with the same name**/
function foo () {<!-- -->
    console.log(1)
}
function foo () {<!-- --> // Overwrite the previous one
    console.log(2)
}
foo(); // 2

/**functions and variables with the same name**/
console.log(foo); // [Function: foo]
var foo = 10;
function foo () {<!-- -->}
console.log(foo); // 10
// Equivalent to ==
function foo () {<!-- -->}
var foo; // ignored
console.log(foo);
foo = 10;
console.log(foo); //10

Benefits of variable promotion

  • Declaration promotion during parsing and precompilation can improve performance, allowing functions to pre-allocate stack space for variables during execution;

Before the JS code is executed, syntax checking and pre-compilation will be performed, and this operation will only be performed once. This is done to improve performance. Without this step, the variable (function) must be re-parsed every time before executing the code. This is unnecessary, because the code of the variable (function) will not change. enough.

During the parsing process, precompiled code is also generated for the function. During precompilation, it will count which variables have been declared and which functions have been created, and the code of the functions will be compressed and comments, unnecessary blanks, etc. will be removed. The advantage of this is that each time a function is executed, stack space can be directly allocated for the function (there is no need to parse it again to obtain which variables are declared in the code and which functions are created), and because of code compression, code execution is also faster. Faster.

  • Statement promotion can also improve the fault tolerance of JS code, so that some non-standard codes can be executed normally.

a = 1;
var a;
console.log(a); // 1
Without variable promotion, these two lines of code would report an error, but with variable promotion, this code can execute normally.

Although in the development process, you can completely avoid writing like this, but sometimes the code is very complex, and it may be used first and then defined due to negligence. However, due to the existence of variable promotion, the code will run normally. Of course, during the development process, try to avoid using variables first and then declaring them.

Problems caused by variable promotion

(1) Variables are overwritten

var name = "JavaScript"
function showName(){<!-- -->
  console.log(name);
  if(0){<!-- -->
   var name = "CSS"
  }
}
showName() //undefined

During function execution, JavaScript will first search for variables from the current execution context. Due to the existence of variable promotion, the current execution context contains the variable name in if(0), and its value is undefined, so the obtained The value of name is undefined.
The output results here are different from other languages that support block-level scope. For example, C language outputs global variables, so it is easy to cause misunderstandings here.

(2) The variable is not destroyed

function foo(){<!-- -->
  for (var i = 0; i < 5; i + + ) {<!-- -->
  }
  console.log(i);
}
foo() // 5

When implementing similar code in most other languages, i has been destroyed after the for loop ends, but in the JavaScript code, the value of i has not been destroyed, so the final printout is 5. This is also caused by variable promotion. During the execution context creation phase, the variable i has been promoted, so when the for loop ends, the variable i has not been destroyed.

Disable variable promotion

To solve the above problems, ES6 introduced the let and const keywords, allowing JavaScript to have block-level scope like other languages. There is no variable promotion for let and const. Let is used below to declare variables:

console.log(num)
let num = 1

// Output result: Uncaught ReferenceError: num is not defined

The variable hoisting mechanism can lead to many misoperations: variables that are forgotten to be declared cannot be clearly detected during the development stage, but are hidden in the code in the form of undefined. In order to reduce runtime errors and prevent undefined from causing unpredictable problems, ES6 specifically imposes a strong constraint on unavailability before declaration. However, there is still a difference between let and const. The value of a variable declared using the let keyword can be changed, while the value of a variable declared using the const cannot be changed.

function fn() {<!-- -->
  let num = 1;
  if (true) {<!-- -->
    let num = 2;
    console.log(num); // 2
  }
  console.log(num); // 1
}
fn()

When this code is executed, the output is as expected. This is because the let keyword supports block-level scope. Therefore, during the compilation phase, the JavaScript engine will not store the variables declared by let in if in the variable environment. This means that the variables declared by let in if will not be stored in the variable environment. Keywords are not promoted to be visible to the whole function. So the value printed within the if is 2, and after jumping out of the block, the value printed is 1. This is in line with our habits: variables declared within the action block do not affect variables outside the block.

3. Temporary dead zone TDZ

ES6 stipulates that if let and const exist in a block, the variables declared by these two keywords in this block will form a closed scope from the beginning. If you try to use this type of variable before declaring it, an error will be reported. The area where errors will be reported in this section is the temporary dead zone. That is, the part in between that is promoted from creation to initialization.

 ...
    if (true) {<!-- -->
       // The creation of a is promoted, the beginning of TDZ
       a = 2; // ReferenceError;
       let a; // Complete the initialization of a and the end of TDZ
       a = 3; // Complete the assignment to a.
   }

Reference cited articles:
https://zhuanlan.zhihu.com/p/438563024
https://juejin.cn/post/6993676334635417614
https://www.xinran001.com/frontend/214.html