let age = 30; console.log(age); // 30 if (true) { let age = 26; console.log(age); // 26 }
暂时性死区
1 2 3 4 5 6
/* 在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone) */ // age 不会被提升 console.log(age); // Uncaught ReferenceError: Cannot access 'age' before initialization let age = 26;
全局声明
与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。
1 2 3 4
var name = "Matt"; console.log(window.name); // 'Matt' let age = 26; console.log(window.age); // undefined
条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。
在页面中定义<script>脚本再次进行声明
1 2 3 4 5 6
// 假设脚本不确定页面中是否已经声明了同名变量 // 那它可以假设还没有声明过 var name = "Nicholas"; // 这里没问题,因为可以被作为一个提升声明来处理 // 不需要检查之前是否声明过同名变量 let age = 26; // Uncaught SyntaxError: Identifier 'age' has already been declared
1 2 3 4 5 6
/* 使用 try/catch 语句或 typeof 操作符也不能解决,因为条件块中 let 声明的作用域仅限于该块。 */ if (typeof name === "undefined") { let name; }
for 循环中的 let 声明
在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部:
1 2 3 4
for (var i = 0; i < 5; ++i) { // 循环逻辑 } console.log(i); // 5
改成使用 let 之后,这个问题就消失了,因为迭代变量的作用域仅限于 for 循环块内部:
1 2 3 4
for (let i = 0; i < 5; ++i) { // 循环逻辑 } console.log(i); // Uncaught ReferenceError: i is not defined
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改:
1 2 3 4 5
for (var i = 0; i < 5; ++i) { // 页面中所有由setTimeout定义的操作,都将放在同一个队列中依次执行。而这个队列的执行时间需要等到函数调用栈执行完毕后才会执行,也就是在循环结束之后,才会轮到setTimeout执行其内部操作,同时,var是函数级作用域,因此在循环结束时i的最终值会更新为5。 setTimeout(() =>console.log(i), 0); } // 输出 5、5、5、5、5
1 2 3 4 5 6
// 在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。 for (let i = 0; i < 5; ++i) { setTimeout(() =>console.log(i), 0); }
// 输出0、1、2、3、4
const
const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误。
1 2
const age = 26; age = 36; // Attempt to assign to const or readonly variable
1 2 3
// const 也不允许重复声明 const name = "Matt"; const name = "Nicholas"; // Duplicate declaration
1 2 3 4 5 6
// const 声明的作用域也是块 const name = "Matt"; if (true) { const name = "Nicholas"; } console.log(name); // Matt