JavaScript 之執行上下文

JavaScript 是如何工做的系列——第三篇

前言

在上篇文章《JavaScript 引擎(V8)是如何工做的》中,咱們介紹了 JavaScript 引擎(V8)是如何執行 JavaScript 代碼的。本篇文章將開始介紹 JavaScript 執行機制中的核心概念——執行上下文。javascript

執行上下文

執行上下文(Execution Context),也稱爲執行環境,就是當前 JavaScript 代碼執行時所在環境的抽象概念。前端

每當開始執行代碼時,JavaScript 引擎會爲整個程序建立一個執行上下文(全局執行上下文),JavaScript 代碼都是在執行上下文中運行的。java

在 JavaScript 中,執行環境主要分爲:git

  • 全局執行上下文(Global Execution Context): 全局執行上下文是最頂層的一個執行環境,是 JavaScript 代碼最開始運行時的默認環境。一個程序中只會有一個全局執行上下文。
  • 函數執行上下文(Function Execution Context):在JavaScript中,每一個函數都有本身的執行上下文。每當一個函數被調用時,就會爲該函數建立一個新的執行上下文。一個程序中能夠有多個函數執行上下文。函數執行上下文能夠訪問全局執行上下文,反之則不行。
  • eval 函數執行上下文: eval 函數在執行其內部代碼時,也會建立屬於本身的執行上下文(由於 eval 函數並不建議使用,因此這裏不作討論)。

咱們看一個例子:github

var a = 'Hello World!'

function helloWorld () {
    var a = 'Hello Function!'
    console.log(a) 
}

helloWorld()
console.log('a)

上述代碼,建立的執行上下文結構以下圖所示:
Image  7segmentfault

顯而易見,在一個 JavaScript 程序中,一般狀況下都會存在多個執行上下文,那麼這些執行上下文是如何管理的呢?數組

JavaScript 引擎建立了執行上下文棧(Execution Context Stack) 來管理執行上下文。瀏覽器

執行上下文棧

首先咱們來了解下什麼是棧數據結構數據結構

棧中數據的存取方式相似給槍上子彈,先上的子彈最後打出,後上的子彈先打出。
特色:先進後出,後進先出函數

瞭解了棧數據結構後,咱們繼續來講執行上下文棧是如何管理執行上下文的?

咱們用數組來模擬執行上下文棧的行爲:ECStack = [];

function fn2() {
  console.log('fn2')
}

function fn1() {
  console.log('fn1')
  fn2();
}

fn1();

上述這段代碼在執行過程當中,執行上下文棧的行爲是什麼樣的?咱們來分析一下:

  1. 在代碼開始執行時,首先會建立全局執行上下文並將其推入到執行上下文棧中;
ECStack.push(global_EC);
  1. 全局上下文入棧後,其中的可執行代碼開始從頂部按順序逐行解釋執行,當調用函數 fn1時,會建立 fn1 函數執行上下文並將其推入到執行上下文棧中;
ECStack.push(fn1_EC);
  1. 以此類推,當開始執行 fn2 時,會建立 fn2 函數執行上下文併入棧;此時全部的執行上下文都已經入棧;
ECStack.push(fn2_EC);

Image  8

  1. 當 fn2 執行完畢,fn2 函數執行上下文出棧;
ECStack.pop();
  1. 當 fn1 執行完畢,fn1 函數執行上下文出棧;
ECStack.pop();
  1. 當全部代碼執行完畢,就又回到了全局執行上下文;當程序退出時,即關閉瀏覽器或網頁時,全局執行上下文才出棧。
ECStack.pop();

Image13

總結:

  • JavaScript 是單線程同步執行的,只有棧頂的上下文處於執行中,其餘上下文須要等待;
  • 全局執行上下文永遠第一個入棧,也就是說它永遠在棧底;而當前執行的函數執行上下文永遠最後一個入棧,也就是說它永遠在棧頂。
  • 執行上下文出棧後,保存在該環境中的全部變量和函數定義也隨之銷燬。

下一篇

在每一個執行上下文中,都包括三個重要的屬性:(ES3版,ES5後作了一些變動,具體變化內容後續會寫文章總結)

  • 變量對象(Variable Object,VO)
  • 做用域鏈(Scope Chain)
  • this指向

Image14

僞代碼以下:

global_EC = {
    scopeChain: {
        // Current scope + scopes of all its parents
    },
    variableObject: {
        // All the variables including inner variables & functions, function arguments
    },
    this: {}
}

下篇文章將開始介紹 JavaScript 的做用域,以及執行上下文中的做用域鏈,敬請期待。

參考:

JavaScript深刻之執行上下文
前端基礎進階(二):執行上下文詳細圖解
JS 執行環境、做用域鏈、活動對象
The Journey of JavaScript From Downloading Scripts to Execution – Part III
相關文章
相關標籤/搜索