我的JS筆記 -- 執(zhí)行上下文


執(zhí)行上下文,就是Js執(zhí)行的時(shí)候的一個(gè)運(yùn)行環(huán)境/作用域(scope)始赎。執(zhí)行上下文決定了Js執(zhí)行過(guò)程中可以獲取哪些變量香璃、函數(shù)这难、數(shù)據(jù),一段程序可能被分割成許多不同的上下文葡秒,每一個(gè)上下文都會(huì)綁定一個(gè)變量對(duì)象(variable object)姻乓,它就像一個(gè)容器,用來(lái)存儲(chǔ)當(dāng)前上下文中所有已定義或可獲取的變量眯牧、函數(shù)等蹋岩。

可執(zhí)行代碼

既然執(zhí)行上下文是在JS執(zhí)行的時(shí)候創(chuàng)建的,那么JS中可執(zhí)行代碼的類型有:

  • 全局代碼学少,這個(gè)是默認(rèn)的代碼運(yùn)行環(huán)境剪个,一旦代碼被載入,引擎最先進(jìn)入的就是這個(gè)環(huán)境版确;
  • 函數(shù)級(jí)別的代碼扣囊,當(dāng)執(zhí)行一個(gè)函數(shù)時(shí),運(yùn)行函數(shù)體中的代碼绒疗;
  • Eval的代碼侵歇,在Eval函數(shù)內(nèi)運(yùn)行的代碼;

執(zhí)行上下文特點(diǎn)

執(zhí)行上下文有以下特點(diǎn):

  • 單線程吓蘑;
  • 同步執(zhí)行惕虑,只有棧頂?shù)纳舷挛奶幱趫?zhí)行中,其他上下文需要等待磨镶;
  • 唯一的一個(gè)全局上下文溃蔫,它在瀏覽器關(guān)閉時(shí)出棧;
  • 函數(shù)的執(zhí)行上下文的個(gè)數(shù)沒(méi)有限制琳猫;
  • 每次某個(gè)函數(shù)被調(diào)用伟叛,就會(huì)有個(gè)新的執(zhí)行上下文為其創(chuàng)建,即使是調(diào)用的自身函數(shù)脐嫂,也是如此痪伦;

執(zhí)行上下文的創(chuàng)建和執(zhí)行

  • 上下文的創(chuàng)建階段:函數(shù)被調(diào)用侄榴,但尚未開(kāi)始執(zhí)行(代碼分析預(yù)處理階段),此時(shí)會(huì)為執(zhí)行上下文創(chuàng)建作用域鏈网沾,創(chuàng)建變量癞蚕、函數(shù)和參數(shù)以及求this的值。也就是發(fā)生聲明提升的階段辉哥,同時(shí)也是產(chǎn)生聲明提升的原因桦山;
  • 執(zhí)行階段:指派變量的值和函數(shù)的引用并解釋執(zhí)行代碼,也就是變量賦值醋旦,函數(shù)引用恒水,執(zhí)行其它代碼,在執(zhí)行階段饲齐,JS引擎會(huì)創(chuàng)建執(zhí)行上下文棧來(lái)管理執(zhí)行上下文钉凌;

簡(jiǎn)單例子:

    var a = 1; // ①
    function f() { // ②
        var a = 2; // ③
        function sayA() { // ④
            console.log(a); // ⑤
        }
        sayA(); // ⑥
    } 
    f(); // ⑦

首先先將執(zhí)行上下文和執(zhí)行上下文棧具象化:

  • 將每個(gè)執(zhí)行上下文看作一個(gè)對(duì)象,它包含三個(gè)屬性:

      ECObj = {
          variableObject: {}, // 變量對(duì)象捂人,函數(shù)中的arguments對(duì)象, 參數(shù), 內(nèi)部的變量以及函數(shù)聲明 
          scopeChain: [], // 作用域鏈御雕,包含執(zhí)行上下文自身變量對(duì)象以及所有父執(zhí)行上下文中的變量對(duì)象,也就是所有可訪問(wèn)的變量和函數(shù)
          this: {} // this指向的對(duì)象
      };
    
  • 將執(zhí)行上下文椑拇睿看作一個(gè)數(shù)組酸纲;

      ECStack = []; // 初始執(zhí)行上下文棧為空數(shù)組
    

上面代碼具體執(zhí)行情況:

  1. 代碼開(kāi)始執(zhí)行之前,首先創(chuàng)建全局執(zhí)行上下文瑟匆;

     globalECObj = {
         variableObject: {
             f: pointer to function f(), // 函數(shù)聲明會(huì)指向該函數(shù)在內(nèi)存中的地址的一個(gè)引用闽坡,所以函數(shù)可以在聲明之前調(diào)用
             a: undefined // 變量聲明初始化會(huì)是undefined
         },
         scopeChain: Object.assign({}, globalECObj.variableObject), // 作用域鏈?zhǔn)侨肿饔糜?     this: window
     };
    
     // 執(zhí)行全局執(zhí)行上下文,全局執(zhí)行上下文入棧
     ECStack.push(globalECObj);
    
  2. 全局執(zhí)行上下文創(chuàng)建完畢愁溜,開(kāi)始執(zhí)行代碼疾嗅,從上至下,① 為賦值操作冕象;

     // ① var a = 1; 給全局變量a賦值
     globalECObj = {
         variableObject: {
             f: pointer to function f(), 
             a: 1
         },
         scopeChain: Object.assign({}, globalECObj.variableObject),
         this: window
     };
    
  3. 跳過(guò)函數(shù)聲明直到遇到可執(zhí)行到代碼 ⑦ 代承;

     // ⑦ f(); 遇到函數(shù)調(diào)用,創(chuàng)建函數(shù)f的執(zhí)行上下文
     fECObj = {
         variableObject: {
             sayA: pointer to function sayA(),
             a: undefined
         },
         scopeChain: Object.assign({}, globalECObj.variableObject, fECObj.variableObject), // 作用域鏈?zhǔn)侨肿饔糜蚝蚮函數(shù)作用域
         this: window
     };
    
     // 函數(shù)f執(zhí)行上下文入棧
     ECStack.push(fECObj);
    
     // 執(zhí)行f執(zhí)行上下文
     // ③ var a = 2; 給局部變量a賦值
     fECObj = {
         variableObject: {
             sayA: pointer to function sayA(),
             a: 2
         },
         scopeChain: Object.assign({}, globalECObj.variableObject, fECObj.variableObject),
         this: window
     }
    
  4. 執(zhí)行函數(shù)f執(zhí)行上下文中又遇到可執(zhí)行代碼 ⑥ 交惯;

     // ⑥ sayA(); 遇到函數(shù)調(diào)用次泽,創(chuàng)建函數(shù)sayA執(zhí)行上下文
     sayAECObj = {
         variableObject: {},
         scopeChain: Object.assign({}, globalECObj.variableObject, fECObj.variableObject, sayAECObj.variableObject), // 作用域鏈?zhǔn)侨肿饔糜蚝蚮函數(shù)作用域和sayA函數(shù)作用域
         this: window
     };
    
     // 函數(shù)sayA執(zhí)行上下文入棧
     ECStack.push(sayAECObj);
    
     // 執(zhí)行sayA執(zhí)行上下文
     2 // 彈出結(jié)果2
    
  5. sayA函數(shù)執(zhí)行結(jié)束穿仪,從執(zhí)行上下文棧彈出

     ECStack.pop();
    
  6. f函數(shù)執(zhí)行結(jié)束席爽,從執(zhí)行上下文棧彈出

     ECStack.pop();
    
  7. 現(xiàn)在只剩全局執(zhí)行上下文了,它會(huì)在瀏覽器關(guān)閉從執(zhí)行上下文棧中彈出

執(zhí)行上下文過(guò)程

  1. JS代碼加載完成啊片;
  2. 創(chuàng)建全局執(zhí)行上下文只锻,為全局執(zhí)行上下文創(chuàng)建作用域鏈,創(chuàng)建變量紫谷、函數(shù)和參數(shù)以及求this的值齐饮;
  3. 全局執(zhí)行上下文入執(zhí)行上下文棧捐寥,開(kāi)始執(zhí)行代碼;
  4. JS為單線程祖驱,從上至下當(dāng)遇到可執(zhí)行代碼握恳,就新建一個(gè)執(zhí)行上下文,為新建執(zhí)行上下文創(chuàng)建作用域鏈捺僻,創(chuàng)建變量乡洼、函數(shù)和參數(shù)以及求this的值;
  5. 新建執(zhí)行上下文入執(zhí)行上下文棧匕坯,開(kāi)始執(zhí)行代碼束昵;
  6. 如果可執(zhí)行代碼中還有可執(zhí)行代碼就重復(fù)4和5;
  7. 執(zhí)行完成的執(zhí)行上下文從執(zhí)行上下文棧頂彈出葛峻;
  8. 關(guān)閉瀏覽器后全局執(zhí)行上下文從執(zhí)行上下文棧中彈出锹雏,執(zhí)行上下文棧清空;

更多文章在 這里 术奖,覺(jué)得不錯(cuò)希望點(diǎn)個(gè) star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末礁遵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腰耙,更是在濱河造成了極大的恐慌榛丢,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挺庞,死亡現(xiàn)場(chǎng)離奇詭異晰赞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)选侨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門掖鱼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人援制,你說(shuō)我怎么就攤上這事戏挡。” “怎么了晨仑?”我有些...
    開(kāi)封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵褐墅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我洪己,道長(zhǎng)妥凳,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任答捕,我火速辦了婚禮逝钥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拱镐。我一直安慰自己艘款,他們只是感情好持际,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哗咆,像睡著了一般蜘欲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晌柬,一...
    開(kāi)封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天芒填,我揣著相機(jī)與錄音,去河邊找鬼空繁。 笑死殿衰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盛泡。 我是一名探鬼主播闷祥,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼傲诵!你這毒婦竟也來(lái)了凯砍?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拴竹,失蹤者是張志新(化名)和其女友劉穎悟衩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栓拜,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡座泳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幕与。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挑势。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖啦鸣,靈堂內(nèi)的尸體忽然破棺而出潮饱,到底是詐尸還是另有隱情,我是刑警寧澤诫给,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布香拉,位于F島的核電站,受9級(jí)特大地震影響中狂,放射性物質(zhì)發(fā)生泄漏凫碌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一吃型、第九天 我趴在偏房一處隱蔽的房頂上張望证鸥。 院中可真熱鬧僚楞,春花似錦勤晚、人聲如沸枉层。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸟蜡。三九已至,卻和暖如春挺邀,著一層夾襖步出監(jiān)牢的瞬間揉忘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工端铛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泣矛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓禾蚕,卻偏偏與公主長(zhǎng)得像您朽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子换淆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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