小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言🛴
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]();
- 结果:
22 原因: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]();
- 结果:
01 原因:跟上述的var声明的变量查找i的过程一样,由于当前作用域没有i,通过作用域链向上查找,由于采用let关键字声明的变量与块级作用域绑定,因此每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的值,也即0,1。- 此题的
关键点在于变量i是全局的,函数执行时输出的时全局作用域下的i值。
最后😎
能不能留下您的小手点个赞呢😘😘😘