成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

「JS篇」JavaScript 執(zhí)行上下文和提升

googollee / 936人閱讀

摘要:執(zhí)行上下文當(dāng)代碼運行的時候,運行代碼的環(huán)境形成了執(zhí)行上下文,執(zhí)行上下文決定代碼可以訪問哪些變量函數(shù)對象等。我們將執(zhí)行上下文簡單視為運行當(dāng)前代碼的,我們知道作用域分為和。完成后,其執(zhí)行堆棧將從堆棧中刪除,將控制權(quán)交給全局執(zhí)行上下文。

我們通常將 JavaScript 歸類為動態(tài)或解釋執(zhí)行語言,但實際上它也是一門編譯語言,它有自己的編譯器形式,運行在 JavaScript 引擎中。

每個 Web 瀏覽器都有自己的 JavaScript 引擎形式:Chrome 有 V8,Mozilla 有 SpiderMonkey 等。這些 JavaScript 引擎的共同點都是將 JavaScript 代碼轉(zhuǎn)換為編譯器可以理解的語言,然后執(zhí)行它。

執(zhí)行上下文 Execution Context

當(dāng) JavaScript 代碼運行的時候,運行 JavaScript 代碼的環(huán)境形成了執(zhí)行上下文 ,執(zhí)行上下文決定代碼可以訪問哪些變量、函數(shù)、對象等。

我們將執(zhí)行上下文簡單視為運行當(dāng)前代碼的 environment / scope,我們知道作用域分為 global scopelocal scope。

類似的,執(zhí)行上下文也分為不同的類型:

全局執(zhí)行上下文 - 代碼首次執(zhí)行時候的默認環(huán)境,在代碼的整個執(zhí)行過程中,只用一個全局執(zhí)行上下文。

函數(shù)執(zhí)行上下文 - 每當(dāng)執(zhí)行流程進入到一個函數(shù)體內(nèi)部的時候,就會創(chuàng)建一個函數(shù)執(zhí)行上下文,可以有任意數(shù)量的函數(shù)執(zhí)行上下文。

執(zhí)行棧/調(diào)用棧

JavaScript 是單線程的,瀏覽器只分配給 JavaScript 一個主線程,一次只能執(zhí)行一個任務(wù)(函數(shù)),因此它在執(zhí)行棧中對其他操作(事件和函數(shù)執(zhí)行)形成一個任務(wù)隊列,排隊等候執(zhí)行。

每當(dāng)在瀏覽器中加載腳本時,棧 stack 中的第一個元素就是全局執(zhí)行上下文。當(dāng)有函數(shù)執(zhí)行時,將創(chuàng)建一個函數(shù)執(zhí)行上下文,并將其置于全局執(zhí)行上下文之上。一旦函數(shù)執(zhí)行完成,它就會從執(zhí)行堆棧中彈出,并將控制權(quán)交給它下面的上下文中。結(jié)合上面說到的,我們看一個例子:

var name = "global variable";
console.log(name)

function func1() {
  console.log("func1 被調(diào)用了。")
  func2();
}
function func2() {
  console.log("func2 被調(diào)用了。");
}
func1();

當(dāng)上述代碼在瀏覽器中加載時:

Javascript 引擎創(chuàng)建一個全局執(zhí)行上下文 global execution context 并將其推送到當(dāng)前執(zhí)行棧。

接著進行 func1() 被調(diào)用,然后 Javascript 引擎為該函數(shù)創(chuàng)建一個新的函數(shù)執(zhí)行上下文 function execution context 并將其推送到全局執(zhí)行上下文的頂部。

在執(zhí)行 func1() 過程中,發(fā)現(xiàn) func2() 被調(diào)用,Javascript 引擎為該函數(shù)創(chuàng)建一個新的執(zhí)行上下文,并將其推送到 func1() 執(zhí)行上下文的頂部。

當(dāng) func2() 函數(shù)完成時,其執(zhí)行上下文從當(dāng)前堆棧彈出,將控制權(quán)交給其下面的執(zhí)行上下文,即 func1() 函數(shù)執(zhí)行上下文。

func1() 完成后,其執(zhí)行堆棧將從堆棧中刪除,將控制權(quán)交給全局執(zhí)行上下文。一旦執(zhí)行了所有代碼,JavaScript 引擎就會從當(dāng)前堆棧中刪除全局執(zhí)行上下文。

執(zhí)行上下文階段

執(zhí)行上下文主要有兩個階段:創(chuàng)建階段執(zhí)行階段,接下來我們將逐一進行介紹。

創(chuàng)建階段

在函數(shù)執(zhí)行發(fā)生之前,JavaScript 引擎會做如下事情:

首先,為每個函數(shù)或變量創(chuàng)建與外部環(huán)境的連接,這些函數(shù)形成作用域鏈 scope chain。作用鏈告訴執(zhí)行上下文它應(yīng)該包含什么,以及它應(yīng)該在哪里查找解析函數(shù)的引用和變量的值。(對于全局環(huán)境,外部環(huán)境為 null。在全局作用域內(nèi)的所有環(huán)境都將把全局環(huán)境作為其外部環(huán)境)。

掃描作用鏈后,將創(chuàng)建一個環(huán)境存儲器,其中全局上下文的創(chuàng)建和引用(Web瀏覽器中的窗口),變量、函數(shù)和函數(shù)參數(shù)的創(chuàng)建和引用在內(nèi)存中完成。

最后,在第一步中創(chuàng)建的每個執(zhí)行上下文中確定 this 關(guān)鍵字的值(對于全局執(zhí)行上下文,this 指向 window)。

我們可以將創(chuàng)建階段使用偽代碼這樣表示:

creationPhase = { // 創(chuàng)建階段
  "outerEnvironmentConnection": { // 創(chuàng)建外部連接
        // 形成作用域鏈
   },    
   "variableObjectMapping": {
        // 變量、函數(shù)和函數(shù)參數(shù)的創(chuàng)建和引用在內(nèi)存中完成。
   },
   "valueOfThis": {},  // 確定 this 的值
}
執(zhí)行階段

這是代碼在創(chuàng)建階段形成的執(zhí)行上下文中的運行的階段,并且逐行分配變量值。

當(dāng)執(zhí)行開始時,JavaScript 引擎在其創(chuàng)建階段對象中查找執(zhí)行函數(shù)的引用。如果在當(dāng)前對象中沒有找到,它將沿著作用域鏈繼續(xù)向上查找,直到它到達全局環(huán)境。

如果在全局環(huán)境中找不到函數(shù)引用,則將返回錯誤。如果找到了引用并且函數(shù)正確執(zhí)行,那么這個特定函數(shù)的執(zhí)行上下文將從棧中彈出,接著 JavaScript 引擎將移動到下一個函數(shù),它們的函數(shù)執(zhí)行上下文將被加入到棧中并執(zhí)行,以此類推。

讓我們通過示例來看看上面的兩個階段,以便更好地理解它。

let name = "webinfoq";
var title = "execution context";
const message = "hello world";

function func1(num) {
  var author = "deepak";
  let value = 3;
  let func2 = function multiply() {
    return num * value;
  }
  const fixed = "Divine";
  function addFive() {
    return num + 5;
  }
}
func1(10);

因此,全局執(zhí)行上下文將如下表示:

globalExecutionObj = {  // 全局執(zhí)行s上下文
    outerEnvironmentConnection: null,  // 全局上下文外部環(huán)境為 null
    variableObjectMapping: { 
        name: uninitialized,  // 在創(chuàng)建階段,let聲明的變量是未初始化狀態(tài)
        title: undefined,   // var 聲明的變量表示為未定義
        date: uninitialized, // 在創(chuàng)建階段,const聲明的變量是未初始化狀態(tài)
        func1: ,  func1 地址引用
    },
    this: window //Global Object  
}
注意:letconst 定義的變量在創(chuàng)建階段沒有任何與之關(guān)聯(lián)的值,但 var 定義的變量在創(chuàng)建階段為 undefined,
這就是為什么可以在 var 聲明之前訪問變量,(得到的是 undefined), 在 letconst
聲明之前訪問會報錯(暫時性死區(qū))。

這就是所謂的變量提升,所有使用 var 聲明的變量都會被提升到作用域的頂部。

執(zhí)行階段,完成對變量的賦值等操作。因此,在執(zhí)行階段,全局執(zhí)行上下文global execution 看起來像這樣:

globalExectutionObj = {  // 全局執(zhí)行上下文
    outerEnvironmentConnection: null,
    variableObjectMapping: {
        name: "webinfoq",
        title: "execution context",
        message: "hello world",
        func1: pointer to function func1, // 指向func1的指針
    },
    this: window //Global Object
}

當(dāng)執(zhí)行到 func1() 時,將形成新的函數(shù)執(zhí)行上下文 function execution global,創(chuàng)建階段如下所示:

func1ExecutionObj = {  // func1 函數(shù)執(zhí)行上下文
    outerEnvironmentConnection: Global,  // 外部環(huán)境為全局環(huán)境
    variableObjectMapping: {
       arguments: {
            0: 10,
            length: 1
        },
        num: 10,
        author: undefined,  // var 聲明的
        value: uninitialized,  // let 聲明的
        func2: uninitialized,  // let 聲明的
        fixed: uninitialized,  // const 聲明
        addFive: pointer to function addFive()  // 指向函數(shù)addFive的指針
    },
    this: Global Object or undefined  
}

執(zhí)行階段:

func1ExecutionObj = {
    outerEnvironmentConnection: Global,  
    variableObjectMapping: {
       arguments: {  // 先處理 arguments 參數(shù)
            0: 10,
            length: 1
        },
        num: 10,
        author: "deepak",  //變量f賦值
        val: 3,
        func2: pointer to function func2() 
        fixed: "Divine"
        addFive: pointer to function addFive()
    },
    this: Global Object or undefined
}

Javascript 引擎創(chuàng)建執(zhí)行上下文,調(diào)用棧。當(dāng)有函數(shù)執(zhí)行時,引擎就會創(chuàng)建一個新的函數(shù)執(zhí)行上下文。最后所用函數(shù)執(zhí)行完成后,將更新全局環(huán)境,然后全局代碼完成,程序結(jié)束。

了解更多請關(guān)注微信公眾號:webinfoq。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105624.html

相關(guān)文章

  • 《高性能JavaScript》讀書筆記

    摘要:除此以外,讓元素脫離文檔流也是一個很好的方法。因為元素一旦脫離文檔流,它對其他元素的影響幾乎為零,性能的損耗就能夠有效局限于一個較小的范圍。講完重排與重繪,往元素上綁定事件也是引起性能問題的元兇。高性能這本書非常精致,內(nèi)容也非常豐富。 showImg(https://segmentfault.com/img/bVJgbt?w=600&h=784); 入手《高性能JavaScript》一...

    W_BinaryTree 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...

    jsbintask 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...

    muddyway 評論0 收藏0
  • JS」你不知道的 JS 知識點總結(jié)(一)

    摘要:調(diào)用棧就是為了到達當(dāng)前執(zhí)行位置所調(diào)用到的所用函數(shù)。方法測試是否至少有一個元素通過由提供的函數(shù)實現(xiàn)的測試返回值是終止。然而,如果存在于原型鏈上層,賦值語句的行為就會有些不同而且可能很出人意料。 typeof null 為 object 解釋 不同的對象在底層都表示為二進制,在JavaScript中二進制前三位都為0的話會被判斷為object類型,null 的二進制表示都是0,自然前三位都...

    JouyPub 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<