初學者指南:深入了解 JavaScript 的建立期與執行期

更新日期: 2024 年 11 月 21 日

在學習 JavaScript 時,理解代碼的執行機制對於寫出穩定、高效的程式碼至關重要。

特別是「建立期」(Creation Phase)和「執行期」(Execution Phase),這兩個階段決定了變數和常數在代碼中的行為。

本文將聚焦於變數的建立期與執行期,幫助新手了解 varletconst 的特性,以及它們在程式執行中的作用。


什麼是建立期與執行期?

每當 JavaScript 引擎執行程式碼時,會為每個執行上下文(Execution Context)創建兩個階段:

  1. 建立期(Creation Phase):在這個階段,JavaScript 引擎會為變數和函式的聲明進行處理,但不會執行任何代碼。
  2. 執行期(Execution Phase):在這個階段,JavaScript 引擎才開始逐行執行代碼,為變數賦值,調用函式等。

變數宣告的建立期與執行期

讓我們以一個簡單的變數宣告代碼為例,來說明建立期和執行期各自做了什麼。

代碼示例:

var a;
console.log(a);

建立期

  • 變數提升(Hoisting)
    • JavaScript 引擎會將使用 var 聲明的變數提升到作用域的頂部。
    • 在建立期,變數 a 被創建並初始化undefined
  • 初始化的意思是為變數設定一個初始值。
    • 在這裡,a 的初始值是 undefined,表示變數已存在但尚未賦予具體的值。

執行期

  • 代碼執行
    • 執行 var a;,但因為已在建立期處理,實際上這行代碼在執行期不做任何事情。
    • 執行 console.log(a);,此時 a 的值為 undefined,因此輸出 undefined

var 變數的特性與可能出現的問題

特性

  • 變數提升var 聲明的變數會在建立期被提升到作用域頂部。
  • 全域或函式作用域var 變數沒有區塊作用域,只受函式或全域作用域限制。

可能的問題

變數提升導致預期外的 undefined

  console.log(a); // 輸出:undefined
  var a = 10;
  • 解釋
    • 在建立期,變數 a 被提升並初始化undefined
    • 在執行 console.log(a); 時,a 還未被賦予真正的值,仍然是 undefined
  • 初始化
    • 在這裡指的是變數已被創建並賦予初始值 undefined,但尚未被賦值為 10

作用域污染

var 變數可能在區塊外被訪問或修改,導致意外的行為。

  if (true) {
    var a = 5;
  }
  console.log(a); // 輸出:5
  • 解釋aif 區塊內聲明,但因為 var 沒有區塊作用域,a 被提升到函式或全域作用域,並初始化undefined,最終被賦值為 5
  • 初始化的過程使得 a 在整個作用域中可用,可能導致意外的結果。

letconst 變數的特性

let 的特性

  • 區塊作用域let 變數只在其所在的區塊內有效。
  • 不會提升為 undefined:在建立期,let 變數被創建但不初始化
  • 補充解釋:這意味著在變數真正聲明並初始化之前,無法訪問該變數。這段期間稱為「暫時性死區」。

const 的特性

  • 區塊作用域:與 let 一樣,const 也具有區塊作用域。
  • 必須初始化const 變數在聲明時必須賦值,且值不可重新賦值。
  • 補充解釋const 變數在建立期被創建,但如果沒有同時進行初始化,會導致語法錯誤。

暫時性死區(Temporal Dead Zone,TDZ)

  • 概念:在區塊作用域內,從代碼的開始到變數被聲明並初始化之前的區域,稱為暫時性死區。
  • 行為:在 TDZ 內訪問 letconst 變數會拋出 ReferenceError

改善了什麼問題?

  • 避免變數提升導致的 undefined 問題:因為在 TDZ 內無法訪問未初始化的變數,避免了誤用未賦值的變數。
  • 提升代碼安全性:強制開發者在使用變數之前進行聲明和初始化。

代碼示例與解釋

let 變數的建立期與執行期

代碼示例:

let a;
console.log(a);

建立期:

  • 變數 a 被創建但不初始化
  • 補充解釋:此時 a 存在於作用域內,但無法被訪問,直到執行期進行初始化。

執行期:

  • 執行 let a;,此時 a初始化undefined
    • 補充解釋:在執行 let a; 時,a 才正式可用,並擁有初始值 undefined
  • 執行 console.log(a);,輸出 undefined

解釋:

  • 雖然 a 在建立期已被創建,但直到執行 let a; 時才被初始化
  • 在這之前訪問 a 會導致 ReferenceError,因為變數尚未被初始化。

const 變數的建立期與執行期

代碼示例:

const a;
console.log(a);

建立期:

  • 變數 a 被創建但不初始化
  • 補充解釋const 變數在建立期被創建,但必須在聲明時進行初始化,否則會產生錯誤。

執行期:

  • 執行 const a;,但因為沒有賦值,會拋出 SyntaxError
  • 補充解釋const 變數要求在聲明的同時進行初始化,缺少初始值會導致語法錯誤。

解釋:

  • const 變數必須在聲明時初始化,否則無法通過語法檢查。

修正代碼:

const a = 10;
console.log(a); // 輸出:10
  • 在建立期a 被創建但未初始化。
  • 在執行期,執行 const a = 10;a初始化10

var 變數在條件語句中的行為

代碼示例:

if (false) {
  var a = 1;
}
console.log(a);

建立期:

  • 變數 a 被提升並初始化undefined
  • 補充解釋:即使條件為 falsevar 聲明的變數仍然在建立期被創建並初始化。

執行期:

  • if 條件為 false,所以區塊內的代碼不執行,a 不會被賦值為 1
  • 執行 console.log(a);,輸出 undefined

解釋:

  • 由於 a 已在建立期被初始化undefined,但執行期沒有賦予新值,所以輸出 undefined
  • 這可能導致預期外的行為,因為變數 a 存在於全域作用域中,但沒有被賦值。

總結

  • var 的問題
    • 變數提升可能導致預期外的 undefined,因為變數在建立期已被初始化undefined
    • 沒有區塊作用域,可能導致作用域污染。
  • letconst 的優勢
    • 擁有區塊作用域,變數只在聲明的區塊內有效。
    • 暫時性死區(TDZ)防止在變數聲明和初始化前訪問變數,提高代碼的安全性。
  • 最佳實踐
    • 儘量使用 letconst,避免使用 var
    • 在使用 const 時,必須同時進行聲明和初始化
    • 注意暫時性死區,確保在變數聲明並初始化後再進行訪問。

結語

理解 JavaScript 的建立期與執行期,以及不同變數聲明方式的特性,能夠幫助你寫出更可靠、可維護的代碼。

透過認識 varletconst 的差異和適用場景,你可以避免許多常見的錯誤,提升程式的品質。


附錄:代碼執行流程總結

var 變數

  • 建立期:變數被提升並初始化undefined
    • 補充解釋:在建立期,變數已存在並擁有初始值 undefined,可在作用域內任何地方訪問。
  • 執行期:在代碼中賦值或修改變數。

letconst 變數

  • 建立期:變數被創建但不初始化,進入暫時性死區。
    • 補充解釋:在建立期,變數已存在於作用域內,但尚未初始化,無法被訪問。
  • 執行期
    • 對於 let,在執行聲明時被初始化undefined
    • 對於 const,在執行聲明時必須同時進行初始化,賦予具體的值。
  • 暫時性死區(TDZ)
    • 從作用域開始到變數聲明並初始化之前的區域。
    • 在 TDZ 內訪問變數會拋出 ReferenceError
  • 補充解釋:TDZ 的存在確保了變數在被正確初始化之前,無法被使用,避免了潛在的錯誤。

希望這篇文章能夠幫助你更好地理解 JavaScript 中的建立期與執行期,以及「初始化」在其中的關鍵作用。

透過深入了解這些概念,你可以在未來的開發中寫出更健壯、可維護的程式碼!

Similar Posts