圖解JS執行上下文
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
執行上下文是什么?執行上下文是一個抽象的概念,用于描述代碼執行時的環境,包含了當前代碼運行時所需的變量、函數和參數。 從一段JS的執行談起單看概念可能還有點懵,其實執行上下文“誕生”的時機是JS代碼編譯的時候,“被操作”的時機是JS代碼執行的時候。 什么樣的JS代碼會被編譯產生執行上下文呢?一般來說,有三種情況:
以這段代碼為例:
這段代碼很簡單,先是創建了一個 add 函數,接著在代碼的最下面又調用了該函數。 那么下面我們就利用圖片來解釋下函數調用的過程。 在執行到函數 add() 之前,JavaScript 引擎會為上面這段代碼創建全局執行上下文,包含了聲明的函數和變量,你可以參考下圖: 從圖中可以看出,代碼中全局變量和函數都保存在全局上下文的變量環境中。 執行上下文準備好之后,便開始執行全局代碼,當執行到 add 這兒時,JavaScript 判斷這是一個函數調用,那么將執行以下操作:
完整流程你可以參考下圖: 就這樣,當執行到 add 函數的時候,我們就有了兩個執行上下文了——全局執行上下文和 add 函數的執行上下文。 也就是說在執行 JavaScript 時,可能會存在多個執行上下文,那么 JavaScript 引擎是如何管理這些執行上下文的呢? 答案是通過一種叫棧的數據結構來管理的。那什么是棧呢?它又是如何管理這些執行上下文呢? 什么是棧關于棧,你可以結合這么一個貼切的例子來理解,一條單車道的單行線,一端被堵住了,而另一端入口處沒有任何提示信息,堵住之后就只能后進去的車子先出來,這時這個堵住的單行線就可以被看作是一個棧容器,車子開進單行線的操作叫做入棧,車子倒出去的操作叫做出棧。 在車流量較大的場景中,就會發生反復的入棧、棧滿、出棧、空棧和再次入棧,一直循環。 所以,棧就是類似于一端被堵住的單行線,車子類似于棧中的元素,棧中的元素滿足后進先出的特點。 你可以參考下圖: 什么是 JavaScript 的調用棧JavaScript 引擎正是利用棧的這種結構來管理執行上下文的。在執行上下文創建好后,JavaScript 引擎會將執行上下文壓入棧中,通常把這種用來管理執行上下文的棧稱為執行上下文棧,又稱調用棧。 為便于你更好地理解調用棧,下面我們再來看段稍微復雜點的示例代碼:
在上面這段代碼中,你可以看到它是在 addAll 函數中調用了 add 函數,那在整個代碼的執行過程中,調用棧是怎么變化的呢? 下面我們就一步步地分析在代碼的執行過程中,調用棧的狀態變化情況。 第一步,創建全局上下文,并將其壓入棧底。如下圖所示:
從圖中你也可以看出,變量 a、函數 add 和 addAll 都保存到了全局上下文的變量環境對象中。全局執行上下文壓入到調用棧后,JavaScript 引擎便開始執行全局代碼了。首先會執行 a=2 的賦值操作,執行該語句會將全局上下文變量環境中 a 的值設置為 2。設置后的全局上下文的狀態如下圖所示:
接下來,第二步是調用 addAll 函數。當調用該函數時,JavaScript 引擎會編譯該函數,并為其創建一個執行上下文,最后還將該函數的執行上下文壓入棧中,如下圖所示: addAll 函數的執行上下文創建好之后,便進入了函數代碼的執行階段了,這里先執行的是 d=10 的賦值操作,執行語句會將 addAll 函數執行上下文中的 d 由 undefined 變成了 10。 然后接著往下執行,第三步,當執行到 add 函數調用語句時,同樣會為其創建執行上下文,并將其壓入調用棧,如下圖所示:
當 add 函數返回時,該函數的執行上下文就會從棧頂彈出,并將 result 的值設置為 add 函數的返回值,也就是 9。如下圖所示:
緊接著 addAll 執行最后一個相加操作后并返回,addAll 的執行上下文也會從棧頂部彈出,此時調用棧中就只剩下全局上下文了。最終如下圖所示:
至此,整個 JavaScript 流程執行結束了。 總結
參考資料:《瀏覽器工作原理與實踐》
該文章在 2024/7/24 16:36:34 編輯過 |
關鍵字查詢
相關文章
正在查詢... |