关于let的那些事儿 (ES6)

316 阅读2分钟

1. 基本用法

ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效

{
  let a=5; 
  console.log(a);   // 5   
}
    console.log(a);  //error:a is not defined

let命令定义的变量a只在块级作用域内生效

  • 用来做for循环的计数器就很合适

    for(let i=0;i<10;i++){ ... } console.log(i); //error: i is not defined

上述代码中,i之在for循环体内生效,在循坏体外则是未定义

  • 另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。(有别于函数定义时的情况)

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

上面代码正确运行,输出了 3 次abc。这表明循环体内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

2.不存在变量提升

  • var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined

    let命令则改变了这一语法现象,它所声明的变量一定要在声明后使用,否则报错。

    // var 的情况
    console.log(a); // undefined
    var a = 2;
    
    // let 的情况
    console.log(b); // error :b is not defined
    let b = 2;
    

    上面代码中,变量a使用var命令声明,会发生变量提升,即将此段声明语句在代码开始运行前就存在了,所以输出结果是undefined(赋值语句还没进行);而变量b是用let命令声明,不会发生变量提前,所以会抛出一个错误 b is not defined

3.暂时性死区

  • 只要块级作用域中存在let命令,它所声明的变量将会被绑定,不受外部作用域的影响。
 //暂时性死区   
 var dead="out_dead"; 
 var alive="out_alive"
    {   
        console.log(dead);    //errer:dead is not defined
        console.log(alive);    // out_alive   
        let dead="in_dead";    
  }

 上述代码中,存在全局变量deadalive,但由于变量dead在代码块内用let命令重新声明,导致变量dead绑定在了块级作用域中,又由于let命令没有变量提升,所以控制台抛出一个错误,相较之下变量alive则可以正常输出。

死区范围演示

if(true){      
  //TDZ开始     
       a="dead";     
       console.log(a);  //error: a is not defined      
       let a; 
 //TDZ结束   

    console.log(a); //undefined    
    a=3;    
    console.log(a); // 3    }

上述代码中,在let语句声明变量a之前,都属于变量a的“暂时性死区

4.不允许重复声明

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

    function func(arg) { let arg; } func() // error

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

上述代码说明,func(arg)的作用域和函数内部的作用域是相同作用域。

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

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

5.let变量与顶层对象

顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。

var a=3;
console.log(window.a); // 3
window.a=5;
console.log(a);  //   5

上述代码表示,顶层对象的属性赋值,与全局变量的属性赋值是一回事;

  • 可能会覆盖window对象原有的属性,造成不必要的程序错误

    var ScreenX="test";

    console.log(window.ScreenX); // 输出结果为 test

  • 解决方案

    let ScreenX="test";

    console.log(window.ScreenX); //浏览器窗口距离屏幕左边的距离

6.只能出现在顶层作用域

// 第一种写法,报错
if (true) let x = 1;

// 第二种写法,不报错
if (true) {
  let x = 1;
}

上面代码中,第一种写法没有大括号,所以不存在块级作用域,而let只能出现在当前作用域的顶层,所以报错。第二种写法有大括号,所以块级作用域成立。

参考文献:阮一峰 《ES6入门教程》  https://es6.ruanyifeng.com/

长路漫漫,共同作伴