深入淺出執(zhí)行上下文鸠补、詞法環(huán)境嘀掸、變量環(huán)境

執(zhí)行上下文的概念

執(zhí)行上下文:javascript 代碼解析和執(zhí)行時所在的環(huán)境。

執(zhí)行上下文的類型

執(zhí)行上下文分為三種類型:

1.全局執(zhí)行上下文

  • js代碼開始運行后睬塌。首先進入全局執(zhí)行上下文環(huán)境中,不在任何函數(shù)中的js代碼都會在全局執(zhí)行上下穩(wěn)重
  • 一個js程序中只存在一個全局執(zhí)行上下文勋陪。創(chuàng)建時會壓人棧底硫兰,只有當程序結(jié)束時才會彈出
  • 全局執(zhí)行上下文會做兩件事。1.創(chuàng)建全局對象瞄崇,2.將this指向這個全局對象
  • 瀏覽器環(huán)境中全局對象是window, 在node環(huán)境中全局對象是global

2.函數(shù)執(zhí)行上下文

  • 函數(shù)每次調(diào)用都會產(chǎn)生一個新的函數(shù)執(zhí)行上下文,每個函數(shù)都擁有自己的執(zhí)行上下文苏研,但是只有調(diào)用的時候才會被創(chuàng)建
  • 函數(shù)執(zhí)行上下文的生命周期分為兩個階段。創(chuàng)建和執(zhí)行

3.Eval執(zhí)行上下文

  • eval函數(shù)執(zhí)行時產(chǎn)生的執(zhí)行上下文筹燕。

執(zhí)行上下文棧

執(zhí)行上下文棧是一個后進先出的數(shù)據(jù)結(jié)構(gòu),
具體執(zhí)行流程如下

  • 首先創(chuàng)建全局執(zhí)行上下文衅鹿, 壓入棧底
  • 每當調(diào)用一個函數(shù)時,創(chuàng)建函數(shù)的函數(shù)執(zhí)行上下文大渤。并且壓入棧頂
  • 當函數(shù)執(zhí)行完成后,會從執(zhí)行上下文棧中彈出泵三,js引擎繼續(xù)執(zhí)棧頂?shù)暮瘮?shù)。

如以下函數(shù)執(zhí)行時的執(zhí)行棧變化為:

function fun1(){
    console.log('func1')
    fun2()
}
function fun2(){
    console.log('func2')
}
fun1()  
/*
*                     fun2
*           fun1      fun1       fun1   
* global => global => global => global => global
*/

執(zhí)行上下文生命周期

變量對象VO和活動對象AO

在講生命周期錢俺抽。我們必須了解講個對象较曼,變量對象VO和活動對象AO

變量對象VO:

  • 用來存儲執(zhí)行上下文中可以被訪問。但不能被delete的函數(shù)標識弛饭。
  • 包括:arguments 對象,形參實參鍵值對孩哑,函數(shù)聲明,變量聲明和this
    活動對象AO:
  • 他可以被理解為當函數(shù)被激活調(diào)用時創(chuàng)建的對象胳蛮。用來訪問VO對象中存儲的那些個標識丛晌。
    全局上下文中變量對象:
  • 就是全局對象
  • 初始化時:初始化一系列原始屬性:Math,String澎蛛,Date,Window等
  • 在瀏覽器中window對象引用全局對象呆馁,全局環(huán)境中this也引用自身

創(chuàng)建階段

此階段執(zhí)行上下文會執(zhí)行以下操作

  • 創(chuàng)建作用域鏈
  • 通過變量對象VO創(chuàng)建活動AO毁兆,
    • 首先創(chuàng)建arguments對象
    • 創(chuàng)建形參實參的鍵值對
    • 創(chuàng)建函數(shù)聲明 (經(jīng)典面試題:為什么函數(shù)聲明提前?)
    • 創(chuàng)建變量聲明 (經(jīng)典面試題:為什么變量聲明提升纺腊?)
  • 創(chuàng)建this

執(zhí)行階段

  • 變量賦值茎芭。函數(shù)引用,執(zhí)行其他代碼邏輯
  • 當執(zhí)行完畢后梅桩。執(zhí)行上下文出棧,等待垃圾回收機制回收

舉例說明

function a(name, age){
    var a = 1
    function c(){}
    var d = funciton (){}
    (function e(){})
    var f = function g(){}
}
a('John')
// 如上代碼煮寡。
//在創(chuàng)建預(yù)編譯階段生成的AO對象如下
AO = {
    arguments:{
        0: 'John',
        1: undefined,
        length: 2
    },
    name: 'John',
    age: undefined,
    c: reference to function c(){},
    a: undefined,
    d: undefined,
    f: undefined,
}
// 函數(shù)表達式 e犀呼,不在AO中 
// 函數(shù)g不在AO中

// 函數(shù)執(zhí)行時AO對象如下
AO = {
    arguments:{
        0: 'John',
        1: undefined,
        length: 2
    },
    name: 'John',
    age: undefined,
    c: reference to function c(){},
    a: 1,
    d: reference to FunctionExpression "d",
    f: reference to FunctionExpression "f",
}

函數(shù)聲明提前

從AO對象的創(chuàng)建過程我們就可以發(fā)現(xiàn)薇组,AO對象想是先掃描函數(shù)體內(nèi)的函數(shù)聲明才去掃描變量聲明。所以這也就是為啥會有聲明提前宋光。

變量提升

AO對象創(chuàng)建時已經(jīng)將函數(shù)內(nèi)部的變量提前掃描聲明。是指在函數(shù)執(zhí)行的過程中開始依次賦值罪佳。

詞法環(huán)境和變量環(huán)境

在ES6中提出詞法環(huán)境和變量環(huán)境兩個概念。主要是執(zhí)行上下文創(chuàng)建過程酌毡。

詞法環(huán)境(LexicalEnvironment)

詞法環(huán)境是一種包含 標識符 => 變量 隱射關(guān)系的一種結(jié)構(gòu)蕾管。

在詞法環(huán)境中有兩個組成部分:

  • 環(huán)境記錄(EnvironmentRecord): 儲存變量和函數(shù)聲明的實際位置
  • 對外部環(huán)境的引用(Outer):當前可以訪問的外部詞法環(huán)境

詞法環(huán)境分為兩種類型:

  • 全局環(huán)境: 全局執(zhí)行上下文,他沒有外部環(huán)境的引用旭蠕,擁有一個全局對象window和關(guān)聯(lián)的方法和屬性eg: Math,String,Date等旷坦。還有用戶定義的全局變量,并將this指向全局對象秒梅。
  • 函數(shù)環(huán)境: 用戶在函數(shù)定義的變量將儲存在環(huán)境記錄中。對外部環(huán)境的引用可以是全局環(huán)境岗屏,也可以是包含內(nèi)部函數(shù)的外部函數(shù)環(huán)境漱办。環(huán)境記錄中包含。用戶聲明的變量娩井。函數(shù)。還有arguments對象咐刨。

舉例詞法環(huán)境在偽代碼中如下:

GlobalExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 剩余標識符
    },
    Outer: null,
  }
}

FunctionExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 剩余標識符
    },
    Outer: [Global or outer function environment reference],
  }
}

變量環(huán)境(VariableEnvironment)

變量環(huán)境也是一個詞法環(huán)境扬霜。他具有詞法環(huán)境中所有的屬性
在ES6中,LexicalEnvironment和VariableEnvironment 的區(qū)別在于前者用于存儲函數(shù)聲明和變量let 和 const 綁定联予,而后者僅用于存儲變量 var 綁定。

用以下代碼舉例:

let a = 20;  
const b = 30;  
var c;

function add(e, f) {  
 var g = 20;  
 function c(){}
 return e + f + g;  
}

c = add(20, 30);

在預(yù)編譯階段沸久。生成的詞法環(huán)境和變量環(huán)境如下

GlobalExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      a: <uninitialied>,
      b: <uninitialied>,
      add: <func>
      // 剩余標識符
    },
    Outer: null,
  },

  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      c: undefined,
      // 剩余標識符
    },
    Outer: null,
  }
}

FunctionExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      arguments: {
        0: 20,
        1: 30,
        length: 2,
      },
      e: 20,
      f: 30,
      c: reference to function c(){}
      // 剩余標識符
    },
    Outer: GlobalLexicalEnvironment,
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      g: undefined,
      // 剩余標識符
    },
    Outer: GlobalLexicalEnvironment,
  }
}

我們發(fā)現(xiàn)使用let和const聲明的變量在詞法環(huán)境創(chuàng)建時是未賦值初始值卷胯。而使用var定義的變量在變量環(huán)境創(chuàng)建時賦值為undefined。這也就是為什么const窑睁、let聲明的變量在聲明錢調(diào)用會報錯,而var聲明的變量不會沙郭。

代碼執(zhí)行階段

此階段的執(zhí)行流程就是函數(shù)執(zhí)行時的流程裳朋。給變量賦值,和執(zhí)行其他邏輯代碼鲤嫡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暖眼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诫肠,更是在濱河造成了極大的恐慌,老刑警劉巖挤安,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丧鸯,死亡現(xiàn)場離奇詭異,居然都是意外死亡围肥,警方通過查閱死者的電腦和手機蜂怎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氢伟,“玉大人,你說我怎么就攤上這事腐芍∈怎铮” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵泣刹,是天一觀的道長犀被。 經(jīng)常有香客問我,道長寡键,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任员舵,我火速辦了婚禮藕畔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘注服。我一直安慰自己,他們只是感情好女淑,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布可很。 她就那樣靜靜地躺著,像睡著了一般苇本。 火紅的嫁衣襯著肌膚如雪菜拓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天俺夕,我揣著相機與錄音,去河邊找鬼劝贸。 笑死,一個胖子當著我的面吹牛映九,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捌议,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼引有,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宫补?” 一聲冷哼從身側(cè)響起导帝,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎您单,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體平酿,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡悦陋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了幸逆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暮现。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拍顷,靈堂內(nèi)的尸體忽然破棺而出塘幅,到底是詐尸還是另有隱情尿贫,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布庆亡,位于F島的核電站捞稿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏括享。R本人自食惡果不足惜珍促,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一猪叙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧穴翩,春花似錦、人聲如沸芒帕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽带膀。三九已至,卻和暖如春垛叨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敛纲。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工还棱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人珍手。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像寡具,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子童叠,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容