首頁 >web前端 >js教程 >JavaScript如何執行上下文

JavaScript如何執行上下文

coldplay.xixi
coldplay.xixi轉載
2021-03-19 10:55:022170瀏覽

JavaScript如何執行上下文

JavaScript中的執行上下文

本文主要會講解我們常看到的上下文知識點,旨在幫助自己和大家加深對它理解。本篇文章可以避開了變數提升相關知識,是希望篇幅可以控制在一定範圍,方便大家瀏覽,劇透一下《變數物件》會在下一篇和大家見面~
持續更新,您的三連就是我最大的動力,虛心接受大佬們的批評與指點,共勉!

目錄

  • 前言
  • 一、怎麼描述執行上下文?
  • 二、執行堆疊
  • 三、形象化執行堆疊
  • 四、思考與總結
  • 五、寫在最後

#相關免費學習推薦:javascript影片教學

#前言

JavaScript如何執行上下文
又到了修練JavaScript內功的時候了,繼上一篇《從作用域到作用域鏈》之後,我們來談一談執行上下文,在寫這篇文章的時候總感覺無法完整的將知識點串聯起來,所以希望大家也能提些建議哦,讓這篇文章更值得收藏、按讚哦~

一、怎麼描述執行上下文

1.1 本節知識導圖:
JavaScript如何執行上下文

1.2 如果描述執行上下文

  1. 當函數執行時,會建立一個稱為執行上下文的內部物件。一個執行上下文定義了一個函數執行時的環境;
  2. 當一個函數被呼叫時,會建立一個活動記錄(有時也稱為執行上下文)。這個記錄會包含函數在哪裡被呼叫(呼叫堆疊)、函數的呼叫方式、傳入的參數等資訊;
  3. 每個函數在被定義時,就會有一個[[scope]]屬性,這個屬性裡保存著作用域鏈,而執行的前一刻都會創建一個OA對象,這個對象就是執行上下文,這個OA對象會被插入[[scope]]中作用域鏈的最頂端,這個對象裡保存著函數體宣告的所有變數、參數和方法。一個OA對象的有序列表。

上述三條描述都符合執行上下文的一些特點,但重點都不一樣。

1.3 執行上下文的型別

  1. #全域執行上下文:只有一個,瀏覽器中的全域物件就是window 對象,this 指向這個全域對象。

  2. 函數執行上下文:存在無數個,只有在函數被呼叫的時候才會被創建,每次呼叫函數都會創建一個新的執行上下文。

  3. Eval 函數執行上下文: 指的是運行在 eval 函數中的程式碼,很少用而且不建議使用。

JavaScript如何執行上下文

二、執行堆疊(Execution context stack)

大家都明白,函數的執行順序和它的定義順序沒關係,但如何解釋,就需要從執行堆疊說起了。

2.1 本節知識導圖

JavaScript如何執行上下文

#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</fun3></fun2></fun1>

注意:除了流程圖,在此送大家2020最新企業級Vue3.0/Js/ES6 /TS/React/Node等實戰視頻教程,點擊此處免費獲取,小白勿進哦

JavaScript如何執行上下文

#再看如下代碼:

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

分析它的執行堆疊經歷了什麼:

JavaScript如何執行上下文
其實到這裡我們已經大致了解了執行堆疊在函數執行前->執行後的流程了,但下一篇文章我們會詳細了解釋一下,感興趣的小伙伴不妨點個關注,不跑丟哦~
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(<checkscope> functionContext);ECStack.push(<f> functionContext);ECStack.pop();ECStack.pop();</f></checkscope>

讓我們模擬第二段程式碼:

ECStack.push(<checkscope> functionContext);ECStack.pop();ECStack.push(<f> functionContext);ECStack.pop();</f></checkscope>

JavaScript如何執行上下文
如果像上一小結一樣畫個圖的話,兩段程式碼確實很不同哦~

相關免費學習推薦:javascript##(影片)

#

以上是JavaScript如何執行上下文的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除