這是研究 JavaScript 內部工作方式的系列文章的第一篇。我會盡力使它變得有趣,並且不讓你感到厭煩,因為我知道這些東西有時會變得非常乏味!
想像一下,飛行員知道是飛機怎樣飛行的,而我們每天運行 JavaScript 代碼,但知道它是如何運行嗎?
談談 JavaScript 執行線程
先讓我們敲出一些簡單的 JavaScript 代碼:
const num = 3;
function addOne(x) {
const result = x + 1;
return result;
}
const output = addOne(num);
上面的代碼沒什麼讓你值得興奮的,但是可以很好地幫助我們演示執行線程。
當執行 JavaScript 時,代碼會逐行(單線程)執行,因此在我們的代碼中,要被執行的第一行是:
1const num = 3;
下一個問題是,執行這行代碼會發生什麼?num 存儲在哪裡?
num 存儲在全局內存/執行上下文中,看起來像這樣:
顯示如何執行第一行的動畫
然後進入下一行:
1function addOne(x) {
請務必注意,我們在這裡聲明了一個函數,但是還不執行。因此,我們將函數名稱與整個函數的值一起存儲。
第二行如何執行
上面的 - f - 是整個函數的簡寫。
現在轉到下一行,有人可能認為下一行是函數的主體,但是由於我們僅聲明函數而不是運行它,因此要運行的下一行是:
1const output = addOne(num);
與上面類似,我們將標籤 output 發送到內存,但還沒有值,因為我們必須運行函數。
保存函數標籤
有趣的來了!接下來執行 addOne 函數。
當一個函數被執行時,它被添加到 call stack (調用棧)中。調用堆棧的底部總是有 global / main ,我們現在將 addOne(3) 入棧。
調用堆棧
我們還為該函數創建一個 execution context (執行上下文)。函數中聲明的任何變量都會被添加到函數的執行上下文中。
將要添加的第一個變量是函數的參數,在本例中為 x 。
添加函數參數
現在,我們移至下一行並將 result 存儲在 execution context 中。
存儲結果
在下一行,用了 return 關鍵字來標記函數的結束。我們從調用棧中彈出 addOne() ,並給 output 賦值為4。
所以首先從 call stack 中彈出 addOne 。
從調用棧彈出
現在是最後一步,將值 4 分配給 output 變量。
最後一步
與上面類似,我們將標籤 output 發送到內存,但還沒有值,因為我們必須運行函數。
保存函數標籤
有趣的來了!接下來執行 addOne 函數。
當一個函數被執行時,它被添加到 call stack (調用棧)中。調用堆棧的底部總是有 global / main ,我們現在將 addOne(3) 入棧。
調用堆棧
我們還為該函數創建一個 execution context (執行上下文)。函數中聲明的任何變量都會被添加到函數的執行上下文中。
將要添加的第一個變量是函數的參數,在本例中為 x 。
添加函數參數
現在,我們移至下一行並將 result 存儲在 execution context 中。
存儲結果
在下一行,用了 return 關鍵字來標記函數的結束。我們從調用棧中彈出 addOne() ,並給 output 賦值為4。
所以首先從 call stack 中彈出 addOne 。
從調用棧彈出
現在是最後一步,將值 4 分配給 output 變量。
每天都會有更新看過的朋友可以點波關注,Java學習路線和優質資源評論或後台回復「Java」獲取。
完成!
就是這些了!我希望這能夠演示 JavaScript 代碼是如何逐步執行的。在本文中提到了 call stack (調用棧)和 execution context (執行上下文),將來我們將會更深入地研究它們。