1. 塊級作用域
在es6以前寫代碼, 通常二話不說, 先寫一段(function(){})()
類似這種的匿名自調(diào)函數(shù). 但是現(xiàn)在想要讓變量不污染全局環(huán)境, 可以有更簡單的寫法.
{
var a = 1;
let b = 1;
}
console.log(window.a); // 1
console.log(window.b); // undefined
這是因為在ES6語法中支持塊級作用域, 使用{}來聲明一個塊級作用域.
并且塊級作用域可以嵌套, 同時子級可以訪問父級的作用域, 但是父級不能訪問子級:
{
let a = 1;
{
console.log(a);
console.log(b); // Uncaught ReferenceError: b is not defined
{
let b = 2;
}
}
}
值得注意的一點是, if/for循環(huán)中()內(nèi)使用let或者const聲明的變量屬于后面的{}, 而不是{}外部:
{
console.log(i); // Uncaught ReferenceError: i is not defined
for (let i = 0; i < 3; i++) {
console.log(i);
}
}
2.暫存性死區(qū)
在相同的函數(shù)或塊作用域內(nèi)重新聲明同一個變量會引發(fā)SyntaxError; 在聲明變量或常量之前使用它, 會引發(fā)ReferenceError. 這就是暫存性死區(qū).
這里主要存在兩個坑點:
- switch case中case語句的作用域
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // TypeError for redeclaration.
break;
}
會報錯是因為switch中只存在一個塊級作用域, 改成以下形式可以避免:
let x = 1;
switch(x) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}
- 與詞法作用域結(jié)合的暫存死區(qū)
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
在if語句中使用了let聲明了foo, 因此在(foo+55)中引用的是if塊級作用域中的foo, 而不是test函數(shù)中的foo; 但是由于if中的foo還沒有聲明完:
在這一行中暂吉,if塊的“foo”已經(jīng)在詞法環(huán)境中創(chuàng)建纵潦,但尚未達到(并終止)其初始化(這是語句本身的一部分)
因此它仍處于暫存死區(qū).
下面的例子也是同樣的問題:
function go(n) {
// n here is defined!
console.log(n); // Object {a: [1,2,3]}
for (let n of n.a) { // ReferenceError: n is not defined
console.log(n);
}
}
go({a: [1, 2, 3]});
指令let n of n.a已經(jīng)在for循環(huán)塊的私有范圍內(nèi),因此標識符“n.a”被解析為位于指令本身的第一部分(“l(fā)et n”)中的'n'對象的屬性'a' 瓮恭,由于尚未達成和終止其聲明,因此仍處于暫存死區(qū)季二。