摘要:當遇到函數調用時,引擎為該函數創建一個新的執行上下文并把它壓入當前執行棧的頂部。參考鏈接理解中的執行上下文和執行棧深入之執行上下文棧
開篇
作為一個JavaScript的程序開發者,如果被問到JavaScript代碼的執行順序,你腦海中是不是有一個直觀的印象 -- JavaScript 是順序執行的,可事實真的是這樣的嗎?
讓我們首先看兩個小例子:
var foo = function () { console.log("foo1"); } foo(); // foo1 var foo = function () { console.log("foo2"); } foo(); // foo2
function foo() { console.log("foo1"); } foo(); // foo2 function foo() { console.log("foo2"); } foo(); // foo2
刷過面試題目的都知道:
JavaScript引擎并非一行一行地分析和執行程序,而是一段一段地分析執行,當執行一段代碼的時候,會進行一個準備工作。
比如我們熟悉的JavaScript中的變量提升比如函數提升都是在這個準備階段完成的。
本文我們就來深入的研究一下,這一段一段中的段是如何劃分的呢?
到底JavaScript引擎遇到一段怎樣的代碼才會做"準備工作"呢?為了解答這個問題我們引入一個概念——執行上下文。
執行上下文如果你做過小學的閱讀理解,肯定見到過這樣的題目:聯系上下文解釋句子,這里的上下文指的可能是這個句子所在的段落,也可能是這個句子所在段落的臨近段落。實際上,這里描述的是一個句子的語境和作用范圍,聯系類比到程序中我們可以作如下定義:
執行上下文是當前JavaScript代碼被解析和執行時所在環境的抽象概念。執行上下文的類型
執行上下文總共分為三種類型,有時候我們也叫做可執行代碼(executable code)
全局執行上下文: 只有一個,瀏覽器中的全局對象就是window對象,this指向這個全局對象。
函數執行上下文: 存在無數個,只有在函數被調用的時候才會被創建,每次調用函數都會創建一個新的執行上下文。
Eval 函數執行上下文: 指的是運行在eval函數中的代碼,很少用而且不建議使用。
舉個例子,當執行到一個函數的時候,就會進行準備工作,這里的"準備工作",讓我們用個更專業一點的說法,就叫做"執行上下文(execution context)"。
執行棧接下來問題來了,我們寫的函數多了去了,如何管理創建的那么多執行上下文呢?所以 JavaScript 引擎創建了執行上下文棧(Execution context stack )ECStack 來管理執行上下文。
這里我們可以簡單的認為 ECStack 是一個數組,類似這樣:
ECStack = [];
執行棧,也叫做調用棧,具有 LIFO(last in first out 后進先出) 結構,用于存儲在代碼執行期間創建的所有執行上下文。
首次運行JavaScript代碼的時候,會創建一個全局執行的上下文并Push到當前的執行棧中,每當發生函數調用,引擎都會為該函數創建一個新的函數執行上下文并Push當前執行棧的棧頂。
當棧頂的函數運行完成后,其對應的函數執行上下文將會從執行棧中Pop出,上下文的控制權將移動到當前執行棧的下一個執行上下文。
讓我們看一段代碼來理解這個過程:
var a = "Hello World!"; function first() { console.log("Inside first function"); second(); console.log("Again inside first function"); } function second() { console.log("Inside second function"); } first(); console.log("Inside Global Execution Context"); // Inside first function // Inside second function // Again inside first function // Inside Global Execution Context
當上述代碼在瀏覽器加載時,JavaScript引擎創建了一個全局執行上下文并把它壓入(push) 當前的執行棧。當遇到 first() 函數調用時,JavaScript引擎為該函數創建一個新的執行上下文并把它壓入當前執行棧的頂部。
當從 first() 函數內部調用 second() 函數時,JavaScript引擎為 second() 函數創建了一個新的執行上下文并把它壓入當前執行棧的頂部,當 second() 函數執行完畢,它的執行上下文會從當前棧彈出(pop),并且控制流程到達下一個執行上下文,即 first() 函數的執行上下文。
當 first() 執行完畢,它的執行上下文從棧中彈出,控制流程到達了全局執行上下文。一旦所有的代碼執行完畢,JavaScript引擎從當前棧中移出全局執行上下文。
下面這張圖,能夠更加清晰的解釋上面這個執行過程
看兩個思考題var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f(); } checkscope();
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()();
兩段代碼執行的結果一樣,但是兩段代碼究竟有哪些不同呢?
答案就是執行上下文棧的變化不一樣。
讓我們模擬第一段代碼:
ECStack.push(functionContext); ECStack.push( functionContext); ECStack.pop(); ECStack.pop();
讓我們模擬第二段代碼:
ECStack.push(functionContext); ECStack.pop(); ECStack.push( functionContext); ECStack.pop();
為了更詳細講解兩個函數執行上的區別,我們需要探究一下執行上下文到底包含了哪些內容,我們需要更加深入了解變量對象的相關內容。
參考鏈接:《理解 JavaScript 中的執行上下文和執行棧》
《JavaScript深入之執行上下文棧》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101738.html
摘要:思考題在深入學習之詞法作用域和動態作用域中,提出這樣一道思考題思考題一思考題二兩段代碼都會打印但是還是有些許差異的,本文就詳細的解析執行上下文棧和執行上下文的具體變化過程。 在《深入學習js之——執行上下文棧》中說過,當JavaScript代碼執行一段可執行代碼(executable code)時,會創建對應的執行上下文(execution context) 對于每一個執行上下文,都有...
摘要:開篇作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習作用域和作用域鏈就是個繞不開的話題。這樣由多個執行上下文的變量對象構成的鏈表就叫做作用域鏈。這時候執行上下文的作用域鏈,我們命名為至此,作用域鏈創建完畢。 開篇 作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習JavaScript,作用域和作用域鏈就是個繞不開的話題。 在《深入學習js之—-執行上下文棧》中我們提到...
摘要:本計劃一共期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅本期推薦文章深入之執行上下文棧和深入之變量對象,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第二天。 本計劃一共28期,每期...
摘要:寫在前面深入系列共計篇已經正式完結,這是一個旨在幫助大家,其實也是幫助自己捋順底層知識的系列。深入系列自月日發布第一篇文章,到月日發布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 深入系列共計 15 篇已經正式完結,這是一個旨在幫助大家,其實也是幫助自己捋順 JavaScript 底層知識的系列。重點講解了如原型、作用域、執行上下文、變量對象、this、...
摘要:深入系列第七篇,結合之前所講的四篇文章,以權威指南的為例,具體講解當函數執行的時候,執行上下文棧變量對象作用域鏈是如何變化的。前言在深入之執行上下文棧中講到,當代碼執行一段可執行代碼時,會創建對應的執行上下文。 JavaScript深入系列第七篇,結合之前所講的四篇文章,以權威指南的demo為例,具體講解當函數執行的時候,執行上下文棧、變量對象、作用域鏈是如何變化的。 前言 在《Jav...
閱讀 1295·2021-11-23 09:51
閱讀 3399·2021-09-06 15:00
閱讀 987·2021-08-16 10:57
閱讀 1370·2019-08-30 12:46
閱讀 933·2019-08-29 12:22
閱讀 1603·2019-08-29 11:07
閱讀 3146·2019-08-26 11:23
閱讀 2980·2019-08-23 15:14