JavaScript ES6 Block Scope - let, const

在 ES6 之前,JavaScript 用 var 關鍵字來宣告一個變數,其作用範圍是 function scope,在 ES6 中引入了兩個新的語法 let 和 const 讓你可以宣告塊級作用範圍 (block scope) 的變數。

所謂的 block scope 就是變數的作用範圍只存在兩個大括號 { } 中。

let

let 關鍵字用來宣告一個 block scope 變數。

// global 變數
var a = 1;

{
    // block scope 變數
    let a = 2;
    
    // 2
    alert(a);
    
    // 重複宣告變數,會發生錯誤
    // TypeError: Identifier 'a' has already been declared
    let a = 3;
}

// 1
alert(a);

另外一個例子:

function varTest() {
    var x = 1;
    
    if (true) {
        // 同樣的 function scope 變數
        var x = 2;
        
        // 2
        alert(x);
    }
    
    // 2
    alert(x);
}

function letTest() {
    let x = 1;
  
    if (true) {
        // 不一樣的 block scope 變數
        let x = 2;
        
        // 2
        alert(x);
    }
  
    // 1
    alert(x);
}

const 常數

const 關鍵字跟 let 類似,也可以用來宣告一個 block scope 變數,不同的是,const 宣告的變數其指向的值不能再被改變。

{
    const A = 10;
    
    // 會發生錯誤,常數值不能再被改變
    // TypeError: Assignment to constant variable
    A = 10;

    // 陣列是一個有趣的例子
    const ARR = [1, 2];
    
    // 可以改變陣列裡的內容
    // 因為 ARR 變數值沒有改變,還是指向同一個陣列
    ARR.push(3);
    
    // [1, 2, 3]
    console.log(ARR);
    
    // 錯誤,不能改常數值
    // TypeError: Assignment to constant variable
    ARR = 123;
    
    // 但可以改變陣列裡面的內容
    ARR[0] = 4;
    
    // [4, 2, 3]
    console.log(ARR);
}

const 還有一個要注意的地方,就是在宣告變數的同時就需要指定值,不然會發生 SyntaxError 錯誤,因為常數的值不能被更改!

// SyntaxError: Missing initializer in const declaration
const foo;
foo = 123;

// 正確的常數宣告方式必須同時賦值
const foo = 123;

一般習慣的 constant variable 命名規則,是全部大寫字母,和可以用底線分隔太長的名稱,例如 CAPITAL_CASING

Temporal Dead Zone

let 和 const 宣告的變數一樣會被 hoist 提升到 scope 的最上方,但和 var 不一樣的是,在變數宣告之前存取變數會造成 ReferenceError 錯誤,因為用 let 和 const 宣告的變數,在程式執行到變數宣告的地方之前,都會暫時被存放在所謂的 Temporal Dead Zone (暫時性死區),不能被存取。

function foo() {

    // 會造成程式錯誤 ReferenceError
    console.log(bar);

    let bar = 101;
}

IE 瀏覽器從 IE11 開始才有支援 let, const。