美文网首页
let关键字

let关键字

作者: 金桔柠檬加冰 | 来源:发表于2018-08-24 11:34 被阅读0次

    1. 作用域

    let关键字:引入let的原因正是var的局限性.

    相比于var,let有以下几点优势:

    • 作用域

      var的作用域是会提升的,var声明的变量只能是全局的或者是整个函数块的

      let则允许声明一个作用域被限制在块级中的变量、语句或者表达式。

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

    分析 :上面代码中使用的是var ,那么最终的输出结果将会是5,因为i虽然在for循环中声明的,但是作用域会被提升到函数块的边界或者直至全局

    ​ 但是如果使用的是let,将会报错,会显示i is not define ,原因就是声明的i被局限于for循环这个块中,出了这个快就找不到i这个变量了,

    ​ 需要注意的是,在程序的顶层,let并不会向var那样将声明的变量加到全局对象上去

    //控制台输出结果
    var i = 5
    undefined
    this.i
    5
    let y = 5
    undefined
    this.y
    undefined
    

    2. 对let块级作用域的使用:

    如果使用var来定义循环控制变量

    var lis = document.querySelector('.test').querySelectorAll('li');
      for(var i = 0 ; i<lis.length;i++){
        lis[i].onclick = function (event) {
           console.log(i);
        }
      }
    //点击li时输出的结果都相同的,都是li的个数
    

    如果使用let

    var lis = document.querySelector('.test').querySelectorAll('li');
    for (let i = 0; i < lis.length; i++) {
          lis[i].onclick = function (event) {
            console.log(i);
          }
      }
    //点击li时输出的结果,为每个li标签的索引
    

    分析

    ​ var 声明的i对应的是全局变量,也就是说i是在循环之外存在的。所以每次点击都对应同一个i,而i是全局的,所以在循环结束后,i的值就已经确定了,因此每次点击出来的都是一样的。

    ​ 但是如果使用了let,那么使用的将是块级作用域,也就是说,每个点击事件都会进入一个不同的块,所以每个点击都会输出正确的序号。

    模仿私有接口

    在处理构造函数的时候,可以通过let绑定来共享一个或多个私有成员,而不使用闭包

    let暂存死区的错误

    在相同的函数或块作用域内重新声明同一个变量会引发SyntaxError

    if (x) {
      let foo;
      let foo; // TypeError thrown.
    }
    //重复声明报错,但是var不会报错
    

    let在包含声明的作用域顶部被创建,通常这种被叫做“变量提升”。但和var不同的是,var的创建会设置一个初试的undefined值,let变量在没有运行到声明代码时是不会被初始化的。引用它将会导致 ReferenceError(而使用 var声明变量则恰恰相反,该变量的值是 undefined )。直到初始化执行的时候,该变量都处于从块开始到初始化处理的“暂存死区”。

    //暂存死区
    function do_something() {
       console.log(x);  //undefined
       console.log(y);  //Uncaught ReferenceError: y is not defined
       var x = 1;
       let y = 2;
    }
    do_something();
    
    

    switch 声明中你可能会遇到这样的错误,因为它只有一个块.

    switch (x) {
      case 0:
        let foo;
        break;
        
      case 1:
        let foo; // TypeError for redeclaration.
        break;
    }
    

    但是,重要的是要指出嵌套在case子句内的块将创建一个新的块作用域的词法环境,这不会产生上面显示的重新声明错误。

    let x = 1;
    
    switch(x) {
      case 0: {
        let foo;
        break;
      }  
      case 1: {
        let foo;
        break;
      }
    }
    

    与词法作用域结合的暂存死区

    由于词法作用域,表达式(foo + 55)内的标识符“foo”会解析为if块的foo,而不是覆盖值为33的foo。在这一行中,if块的“foo”已经在词法环境中创建,但尚未达到(并终止)其初始化(这是语句本身的一部分):它仍处于暂存死区。

    function test(){
       var foo = 33;
       if (true) {
          let foo = (foo + 55); // ReferenceError
       }
    }
    test();
    

    这种现象可能会使您陷入以下情况。指令let n of n.a已经在for循环块的私有范围内,因此标识符“n.a”被解析为位于指令本身的第一部分(“let n”)中的'n'对象的属性'a' ,由于尚未达成和终止其声明,因此仍处于暂存死区。

    function go(n) {
    // n here is defined!
      console.log(n); // Object {a: [1,2,3]}
    
      for (let n of n.a) { // ReferenceError
        console.log(n);
      }
    }
    go({a: [1, 2, 3]});
    

    其他情况

    当在块中使用时,let将变量的作用域限制为该块。注意**var**的作用域在它被声明的函数内的区别。

    var a = 1;
    var b = 2;
    
    if (a === 1) {
      var a = 11; // the scope is global
      let b = 22; // the scope is inside the if-block
      console.log(a);  // 11
      console.log(b);  // 22
    } 
    console.log(a); // 11
    console.log(b); // 2
    

    相关文章

      网友评论

          本文标题:let关键字

          本文链接:https://www.haomeiwen.com/subject/pvjbiftx.html