JavaScript 之執行上下文

tips:
若是發現文中有描述不許確的地方,請必定要在評論區留言告知,十分感謝!
若是本篇文章對你有所幫助,還請幫忙點個贊,你的點贊對我來講是莫大的鼓勵!
github blog: https://github.com/jeuino/Blo...

前言

在上篇文章《JavaScript 之詞法分析和語法分析》中,咱們介紹了詞法分析和語法分析的基本概念。本篇文章將繼續講解什麼是執行上下文。前端

Snipaste_2020-03-10_23-21-35

可能有的讀者會疑惑,預編譯階段和執行代碼階段與執行上下文是什麼關係?這個問題會在講解執行上下文的生命週期時作出解釋。敬請期待《JavaScript 之執行上下文的生命週期》

執行上下文

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

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

  • 全局執行環境: 全局執行環境是最頂層的一個執行環境,是 JavaScript 代碼最開始運行時的默認環境。
  • 函數執行環境:函數執行環境是調用函數時建立的,每次調用函數,都會爲該函數建立一個新的執行上下文。
  • eval 函數執行環境: eval 函數在執行其內部代碼時,也會建立屬於本身的執行上下文。(由於 eval 函數並不建議使用,因此這裏不作介紹。)

在一個 JavaScript 程序中,一般狀況下都會存在多個執行上下文,由於一個 JavaScript 文件中可能聲明瞭多個函數。當多個函數被調用時,就會建立多個執行上下文,那麼這些執行上下文是如何管理的呢?segmentfault

JavaScript 引擎建立了執行上下文棧(Execution Context Stack)(也被稱爲函數調用棧) 來管理執行上下文。數組

執行上下文棧

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

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

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

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

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

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

fn1();

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

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

Image12

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

Image13

總結:

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

下一篇

在每一個執行上下文中,都包括三個重要的屬性:

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

Image14

下篇文章將繼續介紹執行上下文中的變量對象,敬請期待。

參考文章:
JavaScript深刻之執行上下文
前端基礎進階(二):執行上下文詳細圖解
JS 執行環境、做用域鏈、活動對象
相關文章
相關標籤/搜索