Let and Const

Time:2022-2-15

ES6 adds let and const commands to declare variables. The usage is similar to VaR, but it is also different from var.

  1. Let does not have variable promotion
  2. The let command in the scope of block level will cause temporary deadband
  3. Let cannot be declared repeatedly within the same scope
  4. Const is similar to let, but const is used to declare constants

1、 Variable promotion

Before ES6, there was no block level scope in JS, and there were only two forms of JS scope: global scope and function scope

Variable promotion means that the declaration of a variable is promoted to the beginning of its scope (only the declaration of the variable is promoted, not the assignment of the variable). The variable declared by VaR in JS will lead to the promotion of the variable.

console.log(a,1);
    var a = 10;
    console.log(a,2);
    
    Output result:
    undefined 1
    10 2

In the above code, first print variable a, then declare and assign variable a, and finally print variable a again. The printing results are undefined and 10 in turn.
It seems that variable a is used between declarations. In fact, it is a variable promotion. Its actual execution sequence is as follows:

var a;  //  Declare variable
    console. log(a,1);  //  Print uninitialized variable a and the result is undefined
    a = 10;  //  Assign value to variable a
    console. log(a,2);  //  Print variable a with a value of 10

The phenomenon of “variable promotion” caused by VAR command makes the variable can be used before declaration, but this does not conform to the normal coding logic and is easy to causeVariable coverageandGlobal variable pollutionPhenomenon.

1. Variable coverage

    var a = 'first';
    function f(){
        console.log(a,1);
        if(0){
            var a = 'second'
        }
    }
    f();  // undefined 1

At first glance, this code will mistakenly think that the output is “first 1”, because when a variable with the same name in the function scope is declared through VAR, the variable in the function scope is promoted (the variable promotion is completed when the code is precompiled, so it has nothing to do with the logical judgment). The actual execution sequence is as follows:

    var a;
    a = 'first';
    function f(){
        var a;
        console.log(a,1);
        if(0){
            a = 'second'
        }
    };
    f();  // undefined 1

The original intention of the code is to use the value of external a in F (). When if is true, the value of variable a will change, but the value of a in F () will be overwritten as undefined due to variable coverage. Therefore, VAR declaration is easy to cause variable coverage

2. Global variable pollution

    var a = 'hello world!';
    
    for (var i = 0; i < a.length; i++) {
      console.log(a[i]); // h e l l o w o r l d !
    }
    
    console.log(i); // 12

It is not difficult to see from the above code that the counting variable I declared with VaR in the for loop still exists after internal use, and is leaked as a global variable, resulting in global variable pollution.

2、 Let and block level scope

ES6 clearly stipulates that if there are let and const commands in a block, the block forms a closed scope for these declared variables from the beginning, which is called block level scope

In Es5, there are only global scope and function scope, which will cause the variable coverage and global variable pollution mentioned above. In order to solve the problem of variable promotion, ES6 proposes let and const commands, which have no variable promotion phenomenon, so they can only be declared before use. At the same time, a temporary dead zone will be formed in the blocks where let and const commands exist. This variable is no longer affected by external factors. The scope of this block is called block level scope.

1.let

Let is similar to VaR, but let does not promote variables. The declared variablesIt only takes effect in the code block where the let command is located

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

    a // ReferenceError: a is not defined.
    b // 1

Let declared variables will not be promoted. They need to be declared before use, otherwise an error will be reported.

    console.log(a,1);// Uncaught ReferenceError: a is not defined
    let a = 10;
    console.log(a,2);

stayWithin the same scope, it is not allowed to use let to declare the same variable repeatedly

    // Identifier 'a' has already been declared
    function func() {
      let a = 10;
      var a = 1;
    }

    // Identifier 'a' has already been declared
    function func() {
      let a = 10;
      let a = 1;
    }

Therefore, if the function carries external parameters, it is not allowed to redeclare parameters inside the function.

function func(arg) {
      let arg;
    }
    func() // Identifier 'arg' has already been declared
    
    function func() {
      let arg;
    }
    func() // undefined
    
    function func(arg) {
      {
        let arg; // Effective only within {}
      }
    }
    func() // undefined

Let declaring variables will not cause variable overwriting, because the variables declared by them will only take effect in their own scope

    let a = 'first';
    function f(){
        console.log(a,1);
        if(1){
            let a = 'second'
            console.log(a,2)
        };
        console.log(a,3);
    }
    f()
    
    // first 1
    // second 2
    // first 3

Let declares that variables will not be polluted by global variables

    var a = [];
    for (var i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 10
    console.log(i);// 10
    
    let a = [];
    for (let i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 6
    console.log(i);// i is not defined

The part in the for loop where the loop variable is set is the parent scope, and there is a separate child scope inside the loop body. When there is a let declared variable in the loop body, a new block level scope is formed inside each loop

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

Note:When the loop variable is set with let in the for loop, the variable generated by each loop is redeclaredAt this time, the number of cycles is remembered by the JavaScript engine

2. Block level scope

The block level scope added in ES6 is actually formed when variables are declared by let or const commands.

Temporary dead zone

As long as the let command exists in the block level scope, the variables declared by it are bound in this area and are no longer affected by external factors.

Within a code block, a variable is not available until it is declared using the let command. Grammatically, this is called “temporary dead zone” (TDZ)

if (true) {
      //TDZ start
      tmp = 'abc'; // ReferenceError
      console.log(tmp); // ReferenceError
    
      let tmp; //  TDZ end
      console.log(tmp); // undefined
    
      tmp = 123;
      console.log(tmp); // 123
    }

ES6 stipulates that temporary deadband and let and const statements do not have variable promotion, which is mainly to reduce runtime errors and prevent the variable from being used before the variable is declared, resulting in unexpected behavior. Such errors are common in Es5. With this provision, it is easy to avoid such errors.

The essence of temporary dead zone is:As soon as you enter the current scope, the variable to be used already exists, but cannot be obtained. You can obtain and use the variable only when the line of code declaring the variable appears

Block level scope

In fact, the let command in ES6 adds a block level scope to JavaScript

In general, a block level scope is a block enclosed by a pair of braces {} with let or const declared variables inside.
Variables declared by a pair of curly braces {} and internal let or const are all required conditions (if there is internal function declaration function, it shall be considered in combination with the environment)

ES6 allows arbitrary nesting of block level scopes. The inner scope can define variables with the same name as the outer scope.

    {
        {
            {
                {
                    let insane = 'Hello World';
                    { let insane = 'Hello World' }
                }
                console.log(insane,1) // insane is not defined
            }
            var a = 1;
        }
        console.log(a,2) // 1
    };

The emergence of block level scope actually makes the widely used anonymous immediate execution function expression (anonymous Iife) unnecessary.

//Iife writing method
    (function () {
      var tmp = ...;
      ...
    }());
    
    //Block level scope writing
    {
      let tmp = ...;
      ...
    }
Block level scope and function declaration

Whether a function can be declared in a block level scope is still a difficult problem.

Es5 stipulates that functions can only be declared in the top-level scope and function scope.

ES6 introduces block level scope, which explicitly allows functions to be declared in block level scope. ES6 stipulates that in the block level scope, the behavior of the function declaration statement is similar to that of the let and cannot be referenced outside the block level scope.

Although Es5 and ES6 stipulate this, in fact, considering the compatibility of old code, the browser has adopted its own behavior

ES6 stipulates in Appendix B that the implementation of the browser can not comply with the above provisions and has its own behavior.

  1. Allows functions to be declared within a block level scope.
  2. Function declarations are similar to VaR, that is, they are promoted to the head of the global scope or function scope.
  3. At the same time, the function declaration is also promoted to the head of the block level scope.
function f() { console.log('I am outside!'); }
    
    (function () {
        if (false) {
            //Declare function f again
            function f() { console.log('I am inside!'); }
        }
        console.log(f) // undefined
        f();  // Uncaught TypeError: f is not a function
    }());

The actual execution sequence of the above codes is:

function f() { console.log('I am outside!'); }
    
    (function () {
        var f; // undefined
        if (false) {
            //Declare function f again
            function f() { console.log('I am inside!'); }
        }
        console.log(f) // undefined
        f();  // Uncaught TypeError: f is not a function
    }());

In different environments, the way of function declaration processing in block level scope is different,Therefore, generally speaking, functions are not declared within the block level scope. If necessary, it should be written as a function expression

function f() { console.log('I am outside!'); }
    
    (function () {
        if (false) {
            //Declare function f again
            let f = function() { console.log('I am inside!'); }
        }
        console.log(f) // ƒ f() { console.log('I am outside!'); }
        f();  // I am outside!
    }());

3、 Const

Const declares a read-only constant, but once declared, the value of the constant cannot be changed

    const a = 10;
    console.log(a) // 10
    a = 5
    console.log(a) // Assignment to constant variable

Const declared constants need to be initialized immediately. If they are not initialized, an error is reported

    const a; // Missing initializer in const declaration

Const declaration forms the same scope as let, which will form a temporary dead zone and is only valid within the block level scope of the declaration

    if(1){
        const a = 10;
        console.log(a,1) // 10 1
    }
    console.log(a,2) // a is not defined
    
    if(1){
        console.log(a,1) // Cannot access 'a' before initialization
        const a = 10;
    }

Const is a constant declared. Like let, it cannot be declared repeatedly.

    const a = 10;
    const a = '10' // Identifier 'a' has already been declared

Const is a constant declared by const, which is essentially fixed. The value of the memory address it points to is fixed

  1. For simple type data (numeric value, string, Boolean value), the value itself has the memory address pointed to by the variable, so it is equivalent to a constant
  2. For compound type data (objects, arrays, etc.), the memory address pointed to by the variable stores only a pointer to the actual data. Const can only ensure that the pointer is fixed, but the data structure pointed to cannot be controlled
const a = [];
    a.push('Hello');
    //The value of a changes
    a; // ["Hello"]
    //Assignment operation failed
    a = ['world'] // Identifier 'a' has already been declared

If you want to freeze an object, you can use object Free method

const a = Object.freeze([]);
a.push('Hello'); // Cannot add property 0, object is not extensible

But object The freeze method only freezes the current layer of objects. If there are objects inside the object, the objects inside can still be changed

const a = Object. Free ({'name': 'Zhang San','age ':'14', obj: {'address':' No. 1 Zhangjiashan road '}});
a.obj. Address = '1 Panda Avenue'
a.obj. Address // '1 Panda Avenue'

Therefore, when freezing objects, the attributes should be frozen in addition to their own

var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};

4、 Summary

  1. Var declaration of variables will promote variables, which is easy to cause variable coverage and global variable pollution
  2. The variables declared by let and const will form a temporary dead zone, so that they cannot be called before meeting the let declaration, which promotes a good programming concept of declaration before use
  3. Transient deadband and block level scope are not the same concept
  4. In the loop body of the for loop, the block level scope formed by the let declaration forms a new block level scope every loop
  5. Const instruction is a constant when declaring numeric value, string and Boolean value. However, when declaring object, array and other composite type data, it can only ensure that the pointer point remains unchanged, but the change of its internal data structure cannot be guaranteed
  6. If you want to freeze an object, there is an object Freeze method, but only one layer can be frozen. If the object has multiple layers, all attributes should be frozen after traversal

reference:ECMAScript 6 beginner Ruan Yifeng

5、 Tea talk

There is no block level scope in Es5. The block level scope is formed in a pair of {} by let or const commands in ES6.

There is only {}. Is the internal scope block level?

Recommended Today

Ansible combat MySQL installation

Do the preparatory work first, prepare a client, and then equip a master machine. Check connectivity: [[email protected] ~]# ansible mytest -m ping 10.128.25.175| SUCCESS => { “ansible_facts”: { “discovered_interpreter_python”: “/usr/bin/python” }, “changed”: false, “ping”: “pong” } [[email protected] ~]# 1. Ansible module search method 1. Ansible’s yum module search yum module online documentation: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_module.html Example: – […]