目录
一、概述
let是ES6新增的关键字,作用是声明变量。
let a; // 单个声明变量
let b, c, d; // 批量声明变量
let e = 100; // 单个声明变量并赋值
let f = 100, g = 200, h = []; // 批量声明并赋值
使用let声明的变量有如下四个特点。
1)不允许重复声明
2)块级作用域
3)不存在变量提升
4)不影响作用域链
二、详解
不允许重复声明
如下代码所示,let不允许在相同作用域内,重复声明同一个变量。
let a = 100;
let a = 200;
// 报错:Uncaught SyntaxError: Identifier 'a' has already been declared
块级作用域
ES5只有两种作用域,分别是全局作用域和函数作用域。ES6新增了块级作用域,let声明的变量只在当前块级作用域内有效。
{
let dog = "京巴";
console.log(dog); // 京巴
}
console.log(dog); // 报错:Uncaught ReferenceError: dog is not defined
不同作用域之间可以定义同名变量。
{
let dog = "京巴";
{
let dog = "哈士奇"
console.log(dog); // 哈士奇
}
console.log(dog); // 京巴
}
块级作用域完全可以替代匿名函数。
// 匿名函数
(function () {
var dog = "阿拉斯加";
// ...
}());
// 块级作用域
{
let dog = "阿拉斯加";
// ...
}
如下代码所示,var关键字声明的变量会泄漏为全局变量,这种情况可以使用let关键字代替var声明变量,以避免泄漏。
for (var i = 0; i < 10; i++) {
}
console.log(i) // 10
不存在变量提升
let关键字声明的变量不存在变量提升。
console.log(a); // 输出undefined
var a = 2;
console.log(bar); // 报错: Uncaught ReferenceError: bar is not defined
let bar = 2;
不影响作用域链
let关键字声明的变量遵循作用域链的规则,即下级可用上级代码块中的局部变量。
{
let p = "泰迪";
{
console.log(p);
}
}
三、拓展
块级作用域与函数声明
ES5规定函数只能在全局作用域和函数作用域中声明,不能在代码块即ES6提出的块级作用域中声明。如下代码所示,根据ES5的规定,是非法的。但浏览器为了兼容以前的旧代码,对于这种非法操作,并没有报错,且能正常执行。
if (true) {
function func() { }
}
ES6正式引入块级作用域的概念,明确允许在块级作用域中声明函数,但声明的函数仅作用于当前块级作用域。
注意,块级作用域中函数声明的具体行为受环境影响较大,应尽量避免在块级作用域中使用函数声明,若必须使用函数,推荐使用函数表达式的形式。
{
let func = function() { }
}
块级作用域必须有大括号
如下代码所示,省略大括号后报错,报错信息翻译为"词法声明不能出现在单个语句的上下文中",简单说,就是单行的条件语句中,不允许使用let关键字。
// 报错:Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context
if (true) let a = 100;
// 不报错
if (true) {
let a = 100;
}
暂时性死区
如下代码所示,let关键字声明的变量绑定在当前块级作用域,全局声明的变量无效,let声明前赋值语句报错。
var a = 123;
if (true) {
a = 123; // Uncaught ReferenceError: Cannot access 'a' before initialization
let a;
}
ES6明确规定,块级作用域对于其内使用let或const命令声明的变量,从一开始就形成了封闭作用域,凡是在声明之前使用这些变量,都会报错,这种现象在语法上叫暂时性死区。如下代码所示,变量a用let声明前,都属于a的死区,无论什么操作,只要用到变量a,就会报错。
{
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a;
}
如下代码所示,是一个比较隐蔽的暂时性死区的例子。
function func(x = y, y = 2) {
return [x, y];
}
func(); // 报错, y未声明,就将其赋予x
暂时性死区的本质是,只要一进入块级作用域,所有使用let和const声明的变量就已经存在了,但是不可获取,只有等声明变量的那一行代码出现,才可以获取和使用这些变量。