您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript怎么執行上下文,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
一、怎么描述執行上下文
1.1 本節知識導圖:
1.2 如果描述執行上下文
當函數執行時,會創建一個稱為執行上下文的內部對象。一個執行上下文定義了一個函數執行時的環境;
當一個函數被調用時,會創建一個活動記錄(有時候也稱為執行上下文)。這個記錄會包含函數在哪里被調用(調用棧)、函數的調用方式、傳入的參數等信息 ;
每個函數在被定義時,就會有一個[[scope]]屬性,這個屬性里保存著作用域鏈,而執行的前一刻都會創建一個OA對象,這個對象就是執行上下文,這個OA對象會被插入[[scope]]中作用域鏈的最頂端,這個對象里保存著函數體聲明的所有變量、參數和方法。一個OA對象的有序列表。
上述三條描述都符合執行上下文的一些特點,但側重點都不一樣。
1.3 執行上下文的類型
全局執行上下文:只有一個,瀏覽器中的全局對象就是 window 對象,this 指向這個全局對象。
函數執行上下文:存在無數個,只有在函數被調用的時候才會被創建,每次調用函數都會創建一個新的執行上下文。
Eval
函數執行上下文: 指的是運行在 eval 函數中的代碼,很少用而且不建議使用。
二、執行棧(Execution context stack)
大家都明白,函數的執行順序和它的定義順序沒關系,但如何解釋,就需要從執行棧說起了。
2.1 本節知識導圖
2.2 描述執行棧
執行棧,也叫調用棧,具有 LIFO(后進先出)結構,用于存儲在代碼執行期間創建的所有執行上下文。
首次運行JS代碼時,會創建一個全局執行上下文并Push到當前的執行上下文棧中。每當發生函數調用,引擎都會為該函數創建一個新的函數執行上下文并push
到當前執行棧的棧頂。
當棧頂函數運行完成后,其對應的函數執行上下文將會從執行棧中pop
出,上下文控制權將移到當前執行棧的下一個執行上下文。
接下來問題來了,我們寫的函數多了去了,如何管理創建的那么多執行上下文呢?
三、形象化執行棧
我們利用圖片+文字描述的方式來解釋這樣幾段代碼:
3.1 為了模擬執行上下文棧的行為,讓我們定義執行上下文棧為一個數組:
var ECStack = [];
試想當 JavaScript 開始要解釋執行代碼的時候,最先遇到的就是全局代碼,所以初始化的時候首先就會向執行上下文棧壓入一個全局執行上下文,我們用 globalContext
表示它,并且只有當整個應用程序結束的時候,ECStack 才會被清空,所以程序結束之前, ECStack 最底部永遠有個globalContext
:
ECStack.push('globalContext');ECStack // ["globalContext"]
現在 JavaScript 遇到下面的這段代碼了:
function fun1() { fun2();}function fun2() { fun3();}function fun3() { console.log('最后打印3')}fun1(); // 最后打印3
當執行一個函數的時候,就會創建一個執行上下文,并且壓入(push
)執行上下文棧,當函數執行完畢的時候,就會將函數的執行上下文從棧中彈出(pop
)。知道了這樣的工作原理,讓我們來看看如何處理上面這段代碼:
// 偽代碼// fun1()ECStack.push(<fun1> functionContext);// fun1中竟然調用了fun2,還要創建fun2的執行上下文ECStack.push(<fun2> functionContext);// 擦,fun2還調用了fun3!ECStack.push(<fun3> functionContext);// fun3執行完畢ECStack.pop();// fun2執行完畢ECStack.pop();// fun1執行完畢ECStack.pop();// javascript接著執行下面的代碼,但是ECStack底層永遠有個globalContext
再看如下代碼:
console.log(1);function father() { console.log(2); (function child() { console.log(3); }()); console.log(4);}father();console.log(5);//會依次輸出 1 2 3 4 5
分析它的執行棧經歷了什么:
其實到這里我們已經大致了解了執行棧在函數執行前->執行后的流程了。
四、思考題
現在我們已經了解了執行上下文棧是如何處理執行上下文的,所以讓我們看看上篇文章《從作用域到作用域鏈》最后的問題:
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(<checkscope> functionContext);ECStack.push(<f> functionContext);ECStack.pop();ECStack.pop();
讓我們模擬第二段代碼:
ECStack.push(<checkscope> functionContext);ECStack.pop();ECStack.push(<f> functionContext);ECStack.pop();
感謝你能夠認真閱讀完這篇文章,希望小編分享的“JavaScript怎么執行上下文”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。