let 关键字
ES6 新增了 let 命令,用来声明变量。
let 特点
不属于顶层对象 window
使用 var 关键字声明的变量实际上是会挂在 window 对戏那个上面的,例如:
var a = 188
# 等同于
window.a = 188
而下面这段代码就不一样了,使用 let 声明的变量拥有块级作用域,不存在 window 上
let a = 188
console.log(windopw.a) // 报错
不允许重复声明
我们先来看段代码
var a = 1
var a = 6
上面代码使用 var 关键字声明了同名的 a 变量,在内存中表现相当于给 a 赋予了新的值对前者进行了覆盖
而使用 let 声明变量是不允许这种不规范操作的
let a = 168
let a = 168
<!-- Uncaught SyntaxError: Identifier 'a' has already been declared (at -->
不存在变量提升
片段 1
console.log(a) // undefined
var a = 1
片段 2
console.log(a) // 抛出错误
let a = 1
从程序角度来看,let 的形式抛出异常信息更加合理
暂时性死区
只要块级作用域内存在 let 命令,它所声明的变量就绑定在了这个区域,不再受外部的影响。
var a = 5
if (true) {
a = 6
let a
}
// Uncaught ReferenceError: Cannot access 'a' before initialization
上面代码中,存在全局变量 a ,但是块级作用域内 let 又声明了一个局部变量 a ,导致后者绑定这个块级作用域,所以在 let 声明变量前,对 a 赋值会报错。
ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
有时“暂时性死区”比较隐蔽,比如:
function foo(b = a, a = 2) {
console.log(a, b)
}
foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization
块级作用域
let 实际上为 JavaScript 新增了块级作用域
{
let a = 5
}
console.log(a) // undefined
a 变量是在代码块 {} 中使用 let 定义的,它的作用域是这个代码块内部,外部无法访问。
我们再看一个项目中很常见的 for 循环:
for (var i = 0; i < 3; i++) {
console.log('循环内:' + i) // 0、1、2
}
console.log('循环外:' + i) // 3
如果改为 let 会怎么样呢?
for (let i = 0; i < 3; i++) {
console.log('循环内:' + i) // 0、1、2
}
console.log('循环外:' + i) // ReferenceError: i is not defined
继续看下面两个例子的对比,这时 a 的值又是多少呢?
if (false) {
var a = 5
}
console.log(a) // undefined
if (false) {
let a = 5
}
console.log(a)
// Uncaught ReferenceError: a is not defined
思考题
请说出下列输出结果
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
// 3、3、3
但我们的期望是输出结果 0 1 2,怎么做到呢?
方案 1:闭包
for (var i = 0; i < 3; i++) {
(function (j) {
setTimeout(() => {
console.log(j);
});
})(i);
}
方案 2:使用 let
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
大家可以把上面这段代码粘贴到 babel 中:www.babeljs.cn/repl , 看下经过 babel 转化为的 ES5 代码是什么样子的。
大家会发现其实 babel 把这段代码转化成了闭包的形式:
"use strict"
var _loop = function _loop(i) {
setTimeout(function() {
console.log(i)
})
}
for (var i = 0; i < 3; i++) {
_loop(i)
}
相信通过这个思考题,大家对于 let 关键字的使用会有进一步的理解。