JavaScript - 呼叫棧



JavaScript 引擎使用呼叫棧來管理執行上下文。它是 JavaScript 執行引擎跟蹤 JavaScript 程式碼中函式呼叫的重要機制。然而,JavaScript 呼叫棧的工作是在內部執行的,但理解 JavaScript 如何執行函式非常重要。

JavaScript 呼叫棧跟蹤當前需要執行的函式或程式碼塊。它以 LIFO(後進先出)的方式工作。因此,任何新增到呼叫棧頂部的函式都會首先被執行。

JavaScript 呼叫棧如何工作?

每當你執行任何 JavaScript 程式碼時,它都會將全域性執行上下文新增到指令碼中。

當你呼叫任何函式時,JavaScript 引擎會將該函式新增到呼叫棧中。之後,當從外部函式呼叫任何巢狀函式時,它會將巢狀函式新增到呼叫棧中。

當內部函式的執行完成後,它會將該函式從呼叫棧中彈出。接下來,它執行外部函式並將其從呼叫棧中彈出。再次,它開始執行全域性上下文中的程式碼。

當呼叫棧為空時,指令碼停止執行。

讓我們透過示例來了解 JavaScript 呼叫棧。

function two() {
  console.log("this is function two");
}

function one() {
  two();
  console.log("This is function one");
}

one();

上述程式碼將按如下方式執行。

1. 當代碼執行開始時,呼叫棧為空,直到執行到達 one() 函式。

2. 將函式 one() 新增到呼叫棧中。現在,呼叫棧為 [one()]。

3. 執行函式 one() 的第一行,該行呼叫函式 two()。

4. 將函式 two() 新增到呼叫棧中。現在,呼叫棧為 [two(), one()]。

5. 執行函式 two() 的所有行。

6. 返回執行函式 one() 的其餘程式碼行。

7. 從呼叫棧中刪除函式 two()。現在,呼叫棧為 [one()]。

8. 開始執行函式 one() 的其餘程式碼。當函式 one() 的執行完成後,JavaScript 引擎開始執行其餘程式碼。

9. 從呼叫棧中刪除函式 one()。現在,呼叫棧為空。

10. 執行其餘程式碼。

示例

每當我們執行以下程式碼時,它都會在呼叫棧中新增全域性執行上下文。每當它從全域性執行上下文中呼叫任何函式時,它都會將該函式新增到呼叫棧中,並首先開始執行該函式。

當從特定函式呼叫另一個函式時,它會被新增到呼叫棧中,並獲得執行優先順序。

當特定函式的執行完成時,直譯器會將其從呼叫棧中刪除。

每當堆疊佔用的空間超過其大小限制時,它都會丟擲“堆疊溢位”錯誤。

<html>
<body>
   <h2> JavaScript - Call stack </h2>
   <div id = "output"></div>
   <script>

    const output = document.getElementById("output");
    function two() {
        output.innerHTML += "two <br>";
    }

    function one() {
        two();
        output.innerHTML += "one <br>";
    }

    one();
</script>
</body>
</html>

JavaScript 呼叫棧溢位

當呼叫棧的大小超過定義的大小限制時,就會發生呼叫棧溢位 (call stack overflow)。通常情況下,當遞迴函式沒有退出點時,就會發生棧溢位。

例如,在下面的程式碼中,fib() 函式沒有退出點,因此它會丟擲呼叫棧溢位錯誤。

function fib() {
   fib();
}
fib();

JavaScript 是一種單執行緒程式語言。因此,它從上到下逐行執行程式碼。這意味著 JavaScript 程式只能擁有一個呼叫棧,並且一次只能執行一行程式碼。

廣告