JavaScript 核心觀念(4)-執行環境與作用域-執行環境與執行堆疊

前言

若沒有搞清楚執行環境與執行堆疊的觀念在後續開發上其實會很混亂。

執行環境

執行環境

在 JavaScript 每一個函式都有「屬於自己的執行環境」,這一點非常重要。

舉例來講我們無法直接繞過函式去呼叫其他函式

1
2
3
4
5
6
7
function sayHi() {
function sayName() {
console.log('Ray');
}
}

sayName(); // sayName is not defined;

所以說 sayName 就會被限制在 sayHi 中,當然變數也是相同的,就算你已經執行了它也是一樣

1
2
3
4
5
function sayHi() {
var name = 'Ray';
}
sayHi();
console.log(name); // name is not defined;

也因為每一個函式都有屬於自己的作用域以及屬於自己的 this,因此你每一次執行的函式都是不同的執行環境。

其中這個觀念也可以套用在 Node.js 以及瀏覽器中,瀏覽器與 Node.js 在執行時也會建立一個「全域執行環境」,也就是 windowglobal

執行堆疊

執行堆疊

執行堆疊的觀念是建立於執行環境下的,首先這邊有一段程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
function a() {
b();
}

function b() {
c();
}

function c() {
console.log('Ray');
}

a();

JavaScript 在運行上面這一段程式碼時其實是一層一層堆疊上去,而且是在特定的執行環境下運作,上方程式碼中 b() 是建立於 a() 底下的,因此 b() 只會存活於 a(),以此類推 b() 裡面的 c() 也是相同。

前面有講到 JavaScript 在運行這一段程式碼時,是一層一層堆疊上去,但是這邊有一個重點要注意,最底層絕對會是一個全域的執行環境,因此以圖片來表達這一整個函式的執行堆疊就會像這樣

執行堆疊運作模式

因此你的執行堆疊與你函式怎麼宣告是沒有任何關係,主要是與你怎麼呼叫有關係,而在這邊雖然執行堆疊是一層一層疊上去,但函式在釋放時絕對不會是從 a() 開始釋放,而是由最後一個開始釋放

函式釋放

在這邊我們也可以使用瀏覽器來實際運作了解一次執行堆疊的釋放,這邊只需要專注於 Call Stack 即可

執行堆疊釋放順序

我絕對沒有玩什麼倒帶影音梗

因此我們可以注意到執行堆疊的執行順序與釋放是這樣

執行:a() -> b() -> c()
釋放:a() <- b() <- c()

參考文獻

0%