天天看點

JavaScript深入之執行上下文棧

如果要問到 JavaScript 代碼執行順序的話,想必寫過 JavaScript 的開發者都會有個直覺的印象,那就是順序執行,畢竟:

然而去看這段代碼:

列印的結果卻是兩個 <code>foo2</code>。

刷過面試題的都知道這是因為 JavaScript 引擎并非一行一行地分析和執行程式,而是一段一段地分析執行。當執行一段代碼的時候,會進行一個“準備工作”,比如第一個例子中的變量提升,和第二個例子中的函數提升。

但是本文真正想讓大家思考的是:這個“一段一段”中的“段”究竟是怎麼劃分的呢?

到底JavaScript引擎遇到一段怎樣的代碼時才會做“準備工作”呢?

這就要說到 JavaScript 的可執行代碼(executable code)的類型有哪些了?

其實很簡單,就三種,全局代碼、函數代碼、eval代碼。

舉個例子,當執行到一個函數的時候,就會進行準備工作,這裡的“準備工作”,讓我們用個更專業一點的說法,就叫做"執行上下文(execution context)"。

接下來問題來了,我們寫的函數多了去了,如何管理建立的那麼多執行上下文呢?

是以 JavaScript 引擎建立了執行上下文棧(Execution context stack,ECS)來管理執行上下文

為了模拟執行上下文棧的行為,讓我們定義執行上下文棧是一個數組:

試想當 JavaScript 開始要解釋執行代碼的時候,最先遇到的就是全局代碼,是以初始化的時候首先就會向執行上下文棧壓入一個全局執行上下文,我們用 globalContext 表示它,并且隻有當整個應用程式結束的時候,ECStack 才會被清空,是以 ECStack 最底部永遠有個 globalContext:

現在 JavaScript 遇到下面的這段代碼了:

當執行一個函數的時候,就會建立一個執行上下文,并且壓入執行上下文棧,當函數執行完畢的時候,就會将函數的執行上下文從棧中彈出。知道了這樣的工作原理,讓我們來看看如何處理上面這段代碼:

兩段代碼執行的結果一樣,但是兩段代碼究竟有哪些不同呢?

答案就是執行上下文棧的變化不一樣。

讓我們模拟第一段代碼:

讓我們模拟第二段代碼:

是不是有些不同呢?

當然了,這樣概括的回答執行上下文棧的變化不同,是不是依然有一種意猶未盡的感覺呢,為了更詳細講解兩個函數執行上的差別,我們需要探究一下執行上下文到底包含了哪些内容,是以歡迎閱讀下一篇《JavaScript深入之變量對象》。

本人轉載自冴羽(https://github.com/mqyqingfeng)

繼續閱讀