let和const的理解以及let,const,var的区别

 let基本用法
    {
        let a = 1
        var b = 2
    }
    console.log(a)    //Uncaught ReferenceError: a is not defined 未捕获引用错误:a是未定义
    console.log(b)     //2
    概念:在ES6中凡是{}包裹的代码都是块级作用域,凡是在块级作用域中用let const声明的变量都在有一个暂时性死区
    代码块内有效 let 是在代码块内有效,var 是在全局范围内有效
 
    不能重复声明

    let 只能声明一次, var 可以声明多次
  {
        let a = 1;
        let a = 2;
        var b = 3;
        var b = 4;
    }
    console.log(a)     //Uncaught SyntaxError: Identifier 'a' has already been declared 未捕获的语法错误:已声明标识符“a”
    console.log(b)     //4
 
 for 循环计数器很适合用 let
    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);     //10次10
        })
    }

    for (let j = 0; j < 10; j++) {
        setTimeout(function () {
            console.log(j);   //0123456789
        })
    }

 

    另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
    for (var i = 0; i < 3; i++) {
        var i = 'abc';
        console.log(i);     //输出一次abc
    }


    for (let j = 0; j < 3; j++) {
        let j = 'abc';
        console.log(j);     //输出三次abc
    }
   这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

    
不存在变量提升

  var 的情况   
    console.log(b); // 输出undefined
    var b = 2;

 

    let 的情况  
    console.log(a);    // 报错Uncaught ReferenceError: Cannot access 'a' before initialization未捕获的引用错误:无法在初始化之前访问“a”
    let a = 2;

    变量 b 用 var 声明存在变量提升,所以当脚本开始运行的时候,b 已经存在了,但是还没有赋值,所以会输出 undefined。

    变量 a 用 let 声明不存在变量提升,在声明变量 a 之前,a 不存在,所以会报错。
 
 暂时性死区
    只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
    var a = 123;

    if (true) {
      //console.log(a) //Uncaught ReferenceError: Cannot access 'a' before initialization   未捕获的引用错误:无法在初始化之前访问“a”
      a = 'abc'; 
      let a;
      //console.log(a)
    }
    上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
    ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
    总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
 
 
“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。
    typeof x; // Uncaught ReferenceError: Cannot access 'x' before initialization  未捕获的引用错误:无法在初始化之前访问“x”

    let x;
    console.log(typeof x)

  上面代码中,变量x使用let命令声明,所以在声明之前,都属于x的“死区”,只要用到该变量就会报错。因此,typeof运行时就会抛出一个ReferenceError。

    作为比较,如果一个变量根本没有被声明,使用typeof反而不会报错。
    
    typeof y
    console.log(typeof y)   //undefined
    上面代码中,y是一个不存在的变量名,结果返回“undefined”。所以,在没有let之前,typeof运算符是百分之百安全的,永远不会报错。现在这一点不成立了。
    这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。
 
    有些“死区”比较隐蔽,不太容易发现。
     function bar(x = y, y = 2) {
      return [x, y];
    }

    console.log(bar())   // 报错Uncaught ReferenceError: Cannot access 'y' before initialization 未捕获的引用错误:无法在初始化之前访问“y”

    function bar(x = 2, y = x) {
      return [x, y];
    }

    console.log(bar())// [2, 2]

 

上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于“死区”。如果y的默认值是x,就不会报错,因为此时x已经声明了。
 
另外,下面的代码也会报错,与var的行为不同。    
    var x = x;
    console.log(x)    // 不报错
  

    let y = y;
    console.log(y)  // ReferenceError: y is not defined y是未定义的
    

 

    上面代码报错,也是因为暂时性死区。使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。

    ES6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易了。

    总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
 
    const基本用法
    const声明一个只读的常量。一旦声明,常量的值就不能改变。
    const a = 123;
    a = 3;
    console.log(a)    //Uncaught TypeError: Assignment to constant variable.    上面代码表明 未捕获类型错误:分配给常量变量。

    const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
    const a;
    console.log(a)  // SyntaxError: Missing initializer in const declaration   const声明中缺少初始值设定项
 
    上面代码表示,const声明中缺少初始值设定项 ,对于const来说,只声明不赋值,就会报错。

    const的作用域与let命令相同:只在声明所在的块级作用域内有效。
    if (true) {
      const a = 5;
    }
    console.log(a)    //Uncaught ReferenceError: a is not defined    a是未定义的

 

    const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

    
    if (true) {
      console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization 未捕获的引用错误:无法在初始化之前访问“a”
      const a = 5;
    }

 

    上面代码在常量a声明之前就调用,结果报错。

    const声明的常量,也与let一样不可重复声明。

    
    const foo = {};

    为 foo 添加一个属性,可以成功
    foo.prop = 123;
    foo.prop // 123

    将 foo 指向另一个对象,就会报错
    
    上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。
    不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

    下面是另一个例子。

    const a = [];
    a.push('Hello'); // 可执行
    a.length = 0;    // 可执行
    a = ['Dave'];    // 报错Uncaught TypeError: Assignment to constant variable.   未捕获类型错误:分配给常量变量。

 

    上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
  
 
  var,const,let的区别
    var
      支持变量声明与解析
      不支持块级作用域
      允许重复声明
    let
      不支持变量声明与解析
      支持块级作用域
      不允许重复声明
      用let声明的变量或者方法只会在代码块中有效
    const
      不支持变量声明与解析
      支持块级作用域
      不允许重复声明,声明变量,一旦确定不允许被修改
      声明变量必须赋值,不能跟var一样声明后再定义
 

 
 
 
 
posted @ 2019-11-14 21:58  SHY13  阅读(409)  评论(0编辑  收藏  举报