javascript之執(zhí)行上下文

本篇文章參考了https://github.com/mqyqingfeng/Blog/issues/5 這位大佬的github。

js在執(zhí)行一段可執(zhí)行代碼的時候會創(chuàng)建一個執(zhí)行上下文橄仍,對于每一個執(zhí)行上下文都有三個重要屬性绣溜。

  • 變量對象(Variable object,VO)
  • 作用域鏈(Scope chain)
  • this
在全局上下文中,它的變量對象就是全局對象伦仍。

函數(shù)上下文的變量對象也叫活動對象结窘。因為變量對象不可訪問,只有進入一個執(zhí)行上下文,變量對象別激活后,才能被訪問,所以我們叫他活動對象。
執(zhí)行上下文的執(zhí)行過程分為兩段

進入執(zhí)行上下文

在這個階段中充蓝,執(zhí)行上下文會分別創(chuàng)建變量對象隧枫,建立作用域鏈,以及確定this的指向谓苟。

執(zhí)行代碼

創(chuàng)建完成之后官脓,就會開始執(zhí)行代碼,這個時候涝焙,會完成變量賦值卑笨,函數(shù)引用,以及執(zhí)行其他代碼仑撞。

當(dāng)進入執(zhí)行上下文時赤兴,這時候還沒有執(zhí)行代碼,
變量對象會包括:

  1. 函數(shù)的所有形參 (如果是函數(shù)上下文)
    • 由名稱和對應(yīng)值組成的一個變量對象的屬性被創(chuàng)建
    • 沒有實參隧哮,屬性值設(shè)為 undefined
  2. 函數(shù)聲明
    • 由名稱和對應(yīng)值(函數(shù)對象(function-object))組成一個變量對象的屬性被創(chuàng)建
    • 如果變量對象已經(jīng)存在相同名稱的屬性桶良,則完全替換這個屬性
  1. 變量聲明
    • 由名稱和對應(yīng)值(undefined)組成一個變量對象的屬性被創(chuàng)建;
    • 如果變量名稱跟已經(jīng)聲明的形式參數(shù)或函數(shù)相同沮翔,則變量聲明不會干擾已經(jīng)存在的這類屬性

讓我們來看個例子

function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;

}

foo(1);

在進入執(zhí)行上下文后陨帆,這時候的 AO 是:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: undefined,
    c: reference to function c(){},
    d: undefined
}

在代碼執(zhí)行階段,會順序執(zhí)行代碼,根據(jù)代碼歧譬,修改變量對象的值

還是上面的例子岸浑,當(dāng)代碼執(zhí)行完后,這時候的 AO 是:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: 3,
    c: reference to function c(){},
    d: reference to FunctionExpression "d"
}

我們再來看看arguments對象是什么,引用js高程里的話:

調(diào)用函數(shù)時瑰步,會為其創(chuàng)建一個Arguments對象矢洲,并自動初始化局部變量arguments,指代該Arguments對象缩焦。所有作為參數(shù)傳入的值都會成為Arguments對象的數(shù)組元素读虏。

當(dāng)查找變量的時候,會先從當(dāng)前上下文的變量對象中查找袁滥,如果沒有找到盖桥,就會從父級(詞法層面上的父級)執(zhí)行上下文的變量對象中查找,一直找到全局上下文的變量對象题翻,也就是全局對象揩徊。這樣由多個執(zhí)行上下文的變量對象構(gòu)成的鏈表就叫做作用域鏈。
我們來看例子嵌赠。

var scope = "global scope";

  function checkscope() {
    var scope2 = 'local scope';
    return scope2;
  }

  checkscope();
 //1.checkscope被創(chuàng)建
 //保存父元素的變量對象到他的內(nèi)部屬性[[scope]]上
 checkscope.[[scope]] = [globalContext.VO]
// 2.開始執(zhí)行checkscope函數(shù) 創(chuàng)建checkscope的執(zhí)行上下文,同時chec
 ECStack = [
  checkscopeContext,
  globalContext
 ]
 //3.checkscope函數(shù)還需要做一些準(zhǔn)備工作才能執(zhí)行
 // 第一步,復(fù)制[[scope]]屬性創(chuàng)建作用域鏈
   checkscopeContext = {
     Scope: checkscope.[[scope]]
  }
  // 第二步,用arguments創(chuàng)建活動對象塑荒,并初始化
  checkscopeContext = {
    Ao: {
      arguments: {
        length: 0
      },
       scope2: undefined
    },
     Scope: checkscope.[[scope]]
   }
  // 第三步,把自己的活動對象壓入Scope中
   checkscopeContext = {
    AO: {
      arguments: {
         length: 0
       },
       scope2: undefined
    },
    Scope: [AO, checkscope.[[scope]]]
   }
// 4.終于準(zhǔn)備工作做完,可以開始執(zhí)行函數(shù),修改AO的屬性值
 checkscopeContext = {
     AO: {
          arguments: {
            length: 0
          },
     scope2: 'local scope'
     },
     Scope: [AO, [[Scope]]]
 }
// 5.查到了scope2的值,返回后函數(shù) 執(zhí)行完畢,把函數(shù)上下文從執(zhí)行上下文中彈出
 ECStack = [
  globalContext
 ];

再來看一個

function a() {
   var aaa = 123;
   function b(){ //函數(shù)b的創(chuàng)建是在a的執(zhí)行上下文準(zhǔn)備階段創(chuàng)建的,這時候就有了a的AO,所以b創(chuàng)建的時候b.[[scope]] = [a.Ao] = 
      console.log(aaa); 
      aaa=234;
};
   b();
   console.dir(aaa);
};
a();

對于上面的例子

  1. function b有自己的作用域姜挺,內(nèi)部定義了aaa齿税,所以在它的VO中aaa是undefined
  2. function a的VO中也定義了aaa,值是123炊豪;
  3. function b執(zhí)行時會順著它的作用域鏈做變量查找(reference resolution)凌箕,先找 到自己定義的aaa,輸出是undefined词渤,因為自己的VO在作用域鏈的第一個位置牵舱,最先被查找。
  4. 自然缺虐,運行時修改的也是b自己AO中的aaa芜壁,所以不會影響到a中的aaa。

執(zhí)行函數(shù)的時候才開始創(chuàng)建上下文和執(zhí)行上下文V玖!把篓!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纫溃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子韧掩,更是在濱河造成了極大的恐慌紊浩,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坊谁,居然都是意外死亡费彼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門口芍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箍铲,“玉大人,你說我怎么就攤上這事鬓椭〉吆铮” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵小染,是天一觀的道長翘瓮。 經(jīng)常有香客問我,道長裤翩,這世上最難降的妖魔是什么资盅? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮踊赠,結(jié)果婚禮上呵扛,老公的妹妹穿的比我還像新娘。我一直安慰自己臼疫,他們只是感情好择份,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烫堤,像睡著了一般荣赶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸽斟,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天拔创,我揣著相機與錄音,去河邊找鬼富蓄。 笑死剩燥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的立倍。 我是一名探鬼主播灭红,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼口注!你這毒婦竟也來了变擒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤寝志,失蹤者是張志新(化名)和其女友劉穎娇斑,沒想到半個月后策添,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡毫缆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年唯竹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苦丁。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡浸颓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芬骄,到底是詐尸還是另有隱情猾愿,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布账阻,位于F島的核電站蒂秘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淘太。R本人自食惡果不足惜姻僧,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒲牧。 院中可真熱鬧撇贺,春花似錦、人聲如沸冰抢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挎扰。三九已至翠订,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間遵倦,已是汗流浹背尽超。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梧躺,地道東北人似谁。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像掠哥,于是被迫代替她去往敵國和親巩踏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353