let关键字的特点及经典面试题

2,315 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言🛴

let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。

let 是ES6新增的用于声明变量的关键字,用自己的话说,它的出现主要是用来替代 var 关键字的,那使用 let 声明的变量有什么特点呢?🍗

特点🥂

  • let声明的变量只在所处于的块级作用域有效
  • 不存在变量提升
  • 有暂时性死区

块级作用域🧐

块级作用域,就是使用了大括号后产生的作用域,我们来看下面这个代码

if (true) {
    let a = 10;
    console.log(a);     // 10
}

都在同一个大括号内,在同一块级作用域,可以正常打印;那如果打印和变量不在同一个大括号内,会正常打印吗?🍱

if (true) {
    let a = 10;
}
console.log(a);

这里将console.log(a)放在了if语句外,而a是在if语句中定义的,不在同一作用域内,打印的结果为 a is not defined

注意: 使用let关键字声明的变量才有块级作用域,使用var声明的变量不具备块级作用域特性

好处🪐

防止循环变量变成全局变量

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

当我们在用var做循环时,循环变量i在结束循环后依然能访问;但当我们改成let后,结束循环后就访问不到了

for (let i = 0; i < 3; i++) {
​
}
console.log(i);     // i is not defined

不存在变量提升🙌

在ES6之前,变量可以先使用再声明,存在变量提升。而使用let关键字就不会出现这种情况了,必须先是声明再使用,否则就会报错。

a = 10;
console.log(a);     // 10
var a;      
a = 10;
console.log(a);     // 报错
let a;

暂时性死区😮

先看下面的这串代码

var num = 10;
if (true) {
    console.log(num);   // 10
}

正常打印,结果是10。

问题来了—— 那如果我在if语句中用let关键字再定义一个num后,还会正常打印吗?🤷‍♂️

var num = 10;
if (true) {
    console.log(num);
    let num = 20;
}   
// Cannot access 'num' before initialization

这就是 let 的暂时性死区。当作用域内存在用 let 关键字定义的同名变量时,console.log(num) 不会再到此块级作用域外去寻找变量,而作用域内的num是在其后面定义的,就会出现这种情况,无法正常运行。

经典面试题🤦‍♂️

var :以下代码的输出结果🍺

var arr = [];
for (var i = 0; i < 2; i++) {
   arr[i] = function () {
       console.log(i);
   }
}
arr[0]();
arr[1]();
  • 结果:2 2
  • 原因:for循环中循环两次分别给数组arr赋于一个函数,当数组项 arr[0] 调用函数时,由于函数体内(当前作用域)并没有声明i,因此通过作用域链向上查找,而这个循环采用var(var声明的变量不具备块级作用域特性),因此向上作用域即为全局作用域,全局作用域中的i的值为2,因此两次循环调用都为2。
  • 此题的 关键点 在于:每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的值。

let :以下代码的输出结果🍻

var arr = [];
for (let i = 0; i < 2; i++) {
    arr[i] = function () {
        console.log(i);
    }
}
arr[0]();
arr[1]();
  • 结果:0 1
  • 原因:跟上述的var声明的变量查找i的过程一样,由于当前作用域没有i,通过作用域链向上查找,由于采用let关键字声明的变量与块级作用域绑定,因此每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的值,也即0,1。
  • 此题的 关键点 在于变量i是全局的,函数执行时输出的时全局作用域下的i值。

最后😎

能不能留下您的小手点个赞呢😘😘😘

背景1.png