初學者指南:深入了解 JavaScript 的執行環境(Execution Context)
更新日期: 2024 年 11 月 21 日
本文為 JS 底層運作邏輯系列文,第三篇
- 初學者指南:深入了解 JavaScript 中的 Event Loop(事件循環)
- 初學者指南:深入了解 JavaScript 的 Call Stack(呼叫堆疊)
- 初學者指南:深入了解 JavaScript 的執行環境(Execution Context) 👈 所在位置
- 初學者指南:深入了解 JavaScript 的建立期與執行期
- 初學者指南:深入了解 JavaScript 中函式與變數的建立期與執行期差異
在學習 JavaScript 的過程中,理解執行環境(Execution Context)的概念是非常重要的。
它負責管理程式碼的執行,並追蹤變數、函數和 this
的狀態。
當程式運行時,每個函數和程式碼塊都有它自己的執行環境,這影響了變數和函數的可見範圍以及它們的生命週期。
本文將為新手介紹 JavaScript 中的執行環境,並解釋當函數結束後,環境中的變數如何消失,只保留 return
的值。
什麼是執行環境?
xecution Context,也稱為執行環境,是 JavaScript 在運行程式碼時創建的運行環境。每當一段程式或函數被執行時,JavaScript 會為其創建一個新的執行環境。這個執行環境包含了三個重要的組成部分:
- 變數物件(Variable Object, VO):存儲著函數的變數、參數和函數聲明。
- 作用域鏈(Scope Chain):追蹤當前環境中變數的可訪問性,並確定哪些變數可以在函數內部使用。
this
值:指向函數執行時的上下文物件,這個值取決於函數的調用方式。
執行環境是 JavaScript 處理變數、作用域以及 this
的基礎。
Execution Context 的類型
在 JavaScript 中,有兩種主要的執行環境類型:
全域執行環境(Global Execution Context)
這是最初始的執行環境。
當瀏覽器或 Node.js 啟動程式時,會創建一個全域執行環境。
它負責管理全域範圍內的所有變數與函數聲明,並將 this
值設為全域物件(在瀏覽器中是 window
,在 Node.js 中是 global
)。
函數執行環境(Function Execution Context)
每當一個函數被調用時,會為該函數創建一個新的執行環境。
這個環境負責追蹤函數內的變數與參數,並將 this
的值設定為與函數調用方式相關的物件。
函數執行結束後,這個環境將會被銷毀。
執行環境的建立過程
執行環境的建立可以分為二個階段:建立階段、執行階段。
建立階段
在這個階段,JavaScript 引擎會進行以下操作:
- 創建變數物件:所有的變數和函數聲明會被提升(Hoisting),變數會先被初始化為
undefined
,而函數則會被完整地提升到執行環境的頂部,以便可以提前調用。 - 建立作用域鏈:JavaScript 會建立當前執行環境的作用域鏈,確定函數內可以訪問的變數範圍,並記錄對外部作用域的訪問權限。
- 設定
this
值:根據函數的調用方式,為當前執行環境設定合適的this
值,這通常指向調用函數的物件。
執行階段
當 JavaScript 呼叫一個函數時,會為該函數創建一個新的執行環境。這個過程包括:
- 初始化參數和變數:參數會被賦予實際的傳入值,而變數(在使用
var
聲明的情況下)會先被初始化為undefined
。 - 執行程式碼:在變數和參數被初始化後,JavaScript 開始逐行執行程式碼,並對變數進行賦值和操作。
當函數執行完畢後,該函數的執行環境會被銷毀。與此函數相關的所有變數和參數將被清除,無法再被訪問。唯一保留下來的是 return
的結果,這個值會被傳遞給調用該函數的程式碼。
這意味著當函數結束時,內部變數的生命週期也隨之結束,除非有閉包(Closure)機制保存了某些變數,否則它們會被釋放。
建立階段
在建立階段,JavaScript 引擎會準備函數執行所需的環境。
在這個階段,函數中的變數和函數聲明會被提升(Hoisting)至作用域的頂端,變數被初始化為 undefined
,而函數則可以提前調用。
這樣的設計允許我們在函數正式執行之前,已經可以對其進行調用。
範例
console.log(myVar); // 輸出:undefined
var myVar = "Hello World";
console.log(myVar); // 輸出:Hello World
在這個範例中,變數 myVar
被提升到作用域的頂端,因此在變數聲明之前的 console.log(myVar)
不會報錯,而是輸出 undefined
。在變數賦值之後,才會輸出 Hello World
。
說明
當 JavaScript 執行 console.log(myVar)
時,變數 myVar
雖然還沒有被賦值,但它已經被提升並初始化為 undefined
。
這就是變數提升(Hoisting)的效果。
函數聲明也遵循同樣的規則,允許在函數定義之前使用它們。
這樣的行為在建立階段完成,而實際的賦值則會在執行階段進行。
執行階段
執行階段是 JavaScript 開始運行程式碼的時候,這時變數和參數都已經初始化完成,JavaScript 會逐行執行程式碼,並根據程式邏輯對變數進行賦值和操作。
範例
function multiply(a, b) {
let result = a * b;
return result;
}
let total = multiply(5, 10);
console.log(total); // 輸出:50
在這個範例中,當 JavaScript 調用 multiply(5, 10)
時,會先初始化參數 a
和 b
為 5
和 10
,並執行運算。
結果會在函數結束後被返回。
說明
在執行階段,JavaScript 開始處理程式碼邏輯。
此時,變數和參數已經在建立階段初始化完成,因此可以安全地進行操作。
當所有程式碼執行完畢,JavaScript 會進入結束階段,清除執行環境中所有與函數相關的變數和參數。
唯一保留的是 return
的結果,這個結果會傳遞給調用函數的地方。
閉包(Closure)是唯一能在函數結束後保留內部變數的特殊情況。
結語
在 JavaScript 中,執行環境(Execution Context)是管理程式運行過程中的關鍵機制。
理解執行環境的建立階段、執行階段和結束階段,有助於更好地掌握變數提升、作用域鏈以及函數結束後變數的消失。
掌握這一概念,能幫助新手避免常見的錯誤,並撰寫更加清晰、穩定的程式碼。