let/const的暫時性死區


暫時性死區的表現

if (true) {
    console.log(value);//VM58:2 Uncaught ReferenceError: Cannot access 'value' before initialization
    let value = 1;
}

進入當前作用域,在變量聲明之前訪問變量,是無法訪問到的。
這是由於let/const沒有變量提升(提升到作用域頂部),因此通過let/const定義的變量不會被提升到作用域頂部——也就是此時的塊級作用域,因此在聲明之前無法訪問。
但是為什么報錯信息是“Cannot access 'value' before initialization”,而不是我們常見的“value is not defined”呢,這2者有啥區別?
比如以下代碼,由於塊級作用域,外部是沒有value聲明的,所以會報錯“value is not defined”

if (false) {
    let value = 1;
}
console.log(value);//Uncaught ReferenceError: value is not defined

原因排查

我們通過控制台的作用域來看看

if (true) {
	debugger
    let value = 1;
}


從上圖可以看到,控制台的Block作用域里value已經存在了,說明value肯定是被定義了,因此肯定不會報錯“value is not defined”,但是又不法訪問,原因是當前時刻為“before initialization”。
那也就是“defined”和“initialization”是有區別的?

我這樣理解

為了理解以上現象,
參考文章我用了兩個月的時間才理解 let,我們可以把 JS 變量分為「創建create、初始化initialize 和賦值assign」3個步驟。

var 聲明的「創建、初始化和賦值」過程

if (true) {
    console.log(x, y) // undefined,undefined
    var x = 1
    var y = 2
}

執行上述代碼時,會有如下步驟:

  • 找到代碼塊中所有用 var 聲明的變量,在這個環境中「創建」這些變量(即 x 和 y)。
  • 將這些變量「初始化」為 undefined。
  • 開始執行代碼
    x = 1 將 x 變量「賦值」為 1
    y = 2 將 y 變量「賦值」為 2
    也就是var在執行賦值操作之前,就將「創建變量,並將其初始化為 undefined」。因此通過var聲明變量之前,在同一作用域下訪問變量,得到的是undefined。

let 聲明的「創建、初始化和賦值」過程

if (true) {
    console.log(x, y) // Cannot access 'value' before initialization
    let x = 1
    let y = 2
}
  • 找到所有用 let 聲明的變量,在環境中「創建」這些變量
  • 開始執行代碼(注意現在還沒有初始化)
  • 執行let x = 1,將 x 「初始化」,並「賦值」為 1(let x 實現初始化,x = 1實現賦值)
  • 對let y = 2實現相同的步驟

無變量提升

從以上分析來看,

  • 我們平常所說的“變量提升“其實是指將「創建」和「初始化」這2個步驟都提升了
  • var存在變量提升,因為其同時提升了「創建」和「初始化」
  • let/const不存在變量提升,實際上是因為let/const只提升了「創建」,而沒有提升「初始化」

同時,上面的報錯也很好理解了:

  • “value is not defined”是因為變量沒有「創建」
  • “Cannot access 'value' before initialization”是「創建」了變量,但沒「初始化」

因此,所謂暫時性死區,就是不能在初始化之前使用變量。

需要暫時性死區的原因

ES6增加暫時性死區這一特性,主要是為了減少運行時錯誤,防止聲明之前就使用
但是為什么不直接將「創建」過程也不提升呢?
我的理解是由於js是靜態作用域,在代碼編譯的時候就會去分析各作用域的變量對象,因此「創建」過程一定是在代碼執行前完成,也就是一定會被提升,那為了防止大家在聲明之前就使用,就在「初始化」上做文章了,沒有講「初始化」不提升,這樣就不能在聲明之前使用了。

參考:

我用了兩個月的時間才理解 let

阮一峰《ES6標准入門》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM