• 关于ES6的let、const那些事儿


    Babel 转码器

    Babel是广泛使用的一个ES6转换器,将ES6代码转换成ES5代码,从而实现在老版本的浏览器执行。

    let和const命令

    let所声明的变量只在let命令所在的代码块内是有效的。

    {
      let a = 10;
      var b = 1;
    }
    
    a // 10
    b // index.html:16 Uncaught ReferenceError: b is not defined
    

    通过let给出了变量的作用域问题,在我们通常的for循环使用比较方便

            var a = [];
            for (var i = 0; i < 10; i++) {
                a[i] = function () {
                    console.log(i);
                };
            }
    
            for (let i = 0; i < 10; i++) {
                a[i] = function () {
                    console.log(i);
                };
            }
        a[6]()
    //当用var声明变量的时候,发现,在输出框内,输出的值是10,也是就说var定义的i是全局的变量,
    //所以在全局内只有一个i,当后续的值不断写入之后,不断地覆盖之前的值
    //如果使用let定义变量的话,由于作用域是在块级,也就是说,每一次循环都是一个新的变量,所以我们可以输出6
    

    变量提升

    在用var定义变量时,我们可以在声明之前就使用变量,值为underfined,也就是变量提升
    在使用let定义变量时,如果变量没有定义或者说,在变量定义之前就使用变量的话,会报错Uncaught ReferenceError的

            console.log(a);     //undefined
            var a = 10;
    
            console.log(b);     //Uncaught ReferenceError
            let b = 5;
    

    暂时性死区

    只要块级作用域存在let命令,所声明的变量就绑定了这个区域,不再受外部的影响。

    var tmp = 123;
    
    if (true) {
      tmp = 'abc'; // ReferenceError
      let tmp;
    }
    

    报错!也就是首先存在全局变量tmp,在块级作用域中,对tmp的赋值在声明变量之前,导致let声明的tmp绑定了这个块级作用域
    ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。
    凡是在声明之前就使用这些变量,就会报错。
    在let声明变量之前都是不可以使用的,在语法称作暂时性死区

    var tmp = 123;
    if (true) {
        let tmp;
        tmp = 'abc';
        console.log(tmp);   //abc      
    }
    console.log(tmp);      //123
    

    在这种情况下对变量首先进行声明,在之后的使用中也就不会报错了。

    if (true) {
      // TDZ开始
      tmp = 'abc'; // ReferenceError
      console.log(tmp); // ReferenceError
    
      let tmp; // TDZ结束。在let声明之前,tmp都是属于死区
      console.log(tmp); // undefined
    
      tmp = 123;
      console.log(tmp); // 123
    }
    

    “暂时性死区”也意味着typeof不再是一个百分之百安全的操作。在使用typeof的时候报ReferenceError错误,但是没有声明的变量报underfined错误

    function bar(x = y, y = 2) {
      return [x, y];
    }
    
    bar(); // 报错,在将y赋值给x的时候,y是没有被声明的,同样在使用let x=x 的时候,也是会报错的,将x赋值给x,但是后面的x并没有被定义
    

    不允许重复声明

    let不允许在相同的作用域内,重复声明同一个变量

    // 报错
    function func() {
      let a = 10;
      var a = 1;
    }
    
    // 报错
    function func() {
      let a = 10;
      let a = 1;
    }
    

    同时,在函数内部重新声明参数也是不可以的

    function func(arg) {
      let arg;
    }
    func() // 报错
    
    function func(arg) {
      {
        let arg;
      }
    }
    func() // 不报错
    

    块级作用域

    在ES5中,只有全局作用域和函数作用域,没有块级作用域
    块级作用域实现了块级作用域之间的一个嵌套,每一个块级对应都是他的一个作用域,内外层的变量就可以不受影响

    块级作用域和函数声明
    在ES5中,函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明,但是浏览器没有遵循这个规定,也就是说,在浏览器中是不会报错的
    在ES6中,块级作用域必须要有大括号,否则mJavaScript引擎就认为不存在块级作用域。

    const命令

    const声明一个只读的常量。一旦声明,常量的值就不能改变。

    const PI = 3.1415;
    PI // 3.1415
    
    PI = 3;
    // TypeError: Assignment to constant variable.
    

    只声明不在赋值会报错

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

    const的作用域与let命令相同:只在声明所在的块级作用域内有效。

    if (true) {
      const MAX = 5;
    }
    
    MAX // Uncaught ReferenceError: MAX is not defined
    

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
    对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

  • 相关阅读:
    Java基础教程:多线程杂谈——双重检查锁与Volatile
    LeetCode:打印零与奇偶数【1116】
    Java基础教程:多线程基础(6)——信号量(Semaphore)
    LeetCode:交替打印【1115】
    做一件事情的3个关键指标:兴趣、能力和回报
    做一件事情的3个关键指标:兴趣、能力和回报
    Retry模式
    Java技术——String类为什么是不可变的
    2017战略No.2:开始电子化记账
    2017战略No.2:开始电子化记账
  • 原文地址:https://www.cnblogs.com/Indomite/p/13265424.html
Copyright © 2020-2023  润新知