JS執行上下文

執行上下文,即context,也不知道是誰翻譯的,很多的文獻、書籍用的都是這個詞。還記得第一次接觸這個詞時的惆悵、迷惘、不知所措,扶了扶眼鏡,翻開大辭典,仍是翻譯成環境比較接地氣。JS執行上下文,即JS的執行環境。web

執行環境(Execution Context, EC)

當咱們的代碼執行時,會進入到不一樣的執行上下文,即不一樣的環境。在不一樣的環境中,有着不一樣的 scope(做用域),代碼所能訪問到的資源也就不一樣。 在 JS 中,執行環境有以下三種狀況:瀏覽器

  • 全局環境bash

    代碼默認運行的環境,代碼執行時會首先進入全局環境。它是最外圍的一個執行環境,根據 ECMAScript 實現所在的宿主環境的不一樣,表示全局環境的對象也不同。在 web 瀏覽器中,全局環境就是 window 對象。全局變量和函數都是做爲全局對象 window 的變量和方法來建立的。函數

  • 函數環境post

    函數被調用執行時,所建立的執行環境。ui

  • evalthis

    使用 eval 會進入一個新的執行環境,它的變量對象爲全局變量對象或調用者的變量對象。因爲 eval 的毒瘤屬性,通常不推薦使用,可忽略。spa

某個執行環境中的全部代碼執行完畢後,該環境被銷燬,保存在環境中的變量和函數也隨之銷燬。這些變量和函數保存在一個叫作變量對象的對象(variableObject)中,關於變量對象將在變量對象與做用域鏈一文做詳細探討。線程

執行環境的生命週期

執行環境的生命週期大概分爲兩個階段,即建立階段和執行階段:翻譯

1. 建立階段

  • 建立做用域鏈(變量對象+父級執行環境的變量對象)
  • 建立變量對象(包括局部變量、函數以及函數參數)
  • 肯定 this 的指向

由此,一個執行環境能夠由包含做用域鏈、變量對象和 this 指針的對象組成:

executionContextObj = {
  scopeChain: {},
  variableObject: {},
  this: {}
}
複製代碼

2. 代碼執行階段

  • 指定變量的值和函數的引用
  • 解釋並執行代碼

執行環境棧(Execution Context Stack, ECS)

瀏覽器中的解釋器被實現爲單線程,同一時間只能處理一個任務,JS 程序中多個執行環境會以棧的方式來處理,這個棧叫作執行棧。棧底永遠都是全局環境(窗口關閉時彈出),棧頂就是當前正在執行的環境。前述三種狀況都會建立執行環境,執行環境建立時會被壓入棧頂,成爲一個運行(活動)的環境,位於棧頂的環境執行完畢後就從棧頂彈出,並將環境控制權交給調用者(以前的棧),而調用者繼續執行(或激活其餘環境),直到它的執行環境結束。ECMAScript 程序中的執行流正是由這個方便的機制控制着。

來看下面的例子:

var firstName = 'snow';

function getName() {
    var lastName = 'John';

    function fullName() {
      var name = lastName + firstName;
      return name;
    }
    var name = fullName();
    return name;
}

getName();
複製代碼

其執行棧變化過程以下:

  • 首先,將全局環境壓入棧,開始執行代碼,

  • 直到遇到getName(),準備調用函數,建立函數 getName 的執行環境,將其壓入棧頂並開始執行函數

  • 直到遇到fullName(),準備調用函數,建立函數 fullName 的執行環境,將其壓入棧頂並開始執行函數

    fullName入棧
  • 函數 fullName 執行時沒有再生成執行環境,執行完畢後則從棧頂彈出

    fullName出棧
  • fullName 執行棧彈出後,控制權回到了 getName 的執行棧,繼續執行代碼,執行完畢,從棧頂彈出

  • 最後回到了全局環境,窗口關閉後彈出 執行棧示意圖

結論

  • 單線程,同步執行,只有棧頂的環境處於執行中,其他環境須要等待。
  • 執行 JS 程序,首先進入全局環境,全局環境只有一個並在關閉窗口時彈出。
  • 函數調用時會建立新的執行環境,包括調用本身。
相關文章
相關標籤/搜索