日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

通過實例了解JS執行上下文運行原理

瀏覽:207日期:2024-05-03 14:11:15

壹 ❀ 引

我們都知道,JS代碼的執行順序總是與代碼先后順序有所差異,當先拋開異步問題你會發現就算是同步代碼,它的執行也與你的預期不一致,比如:

function f1() { console.log(’聽風是風’);};f1(); //echofunction f1() { console.log(’echo’);};f1(); //echo

按照代碼書寫順序,應該先輸出 聽風是風,再輸出 echo才對,很遺憾,兩次輸出均為 echo;如果我們將上述代碼中的函數聲明改為函數表達式,結果又不太一樣:

var f1 = function () { console.log(’聽風是風’);};f1(); //聽風是風var f1 = function() { console.log(’echo’);};f1(); //echo

這說明代碼在執行前一定發生了某些微妙的變化,JS引擎究竟做了什么呢?這就不得不提JS執行上下文的了。

貳 ❀ JS執行上下文

JS代碼在執行前,JS引擎總要做一番準備工作,這份工作其實就是創建對應的執行上下文;

執行上下文有且只有三類,全局執行上下文,函數上下文,與eval上下文;由于eval一般不會使用,這里不做討論。

1.全局執行上下文

全局執行上下文只有一個,在客戶端中一般由瀏覽器創建,也就是我們熟知的window對象,我們能通過this直接訪問到它。

通過實例了解JS執行上下文運行原理

全局對象window上預定義了大量的方法和屬性,我們在全局環境的任意處都能直接訪問這些屬性方法,同時window對象還是var聲明的全局變量的載體。我們通過var創建的全局對象,都可以通過window直接訪問。

通過實例了解JS執行上下文運行原理

2.函數執行上下文

函數執行上下文可存在無數個,每當一個函數被調用時都會創建一個函數上下文;需要注意的是,同一個函數被多次調用,都會創建一個新的上下文。

說到這你是否會想,上下文種類不同,而且創建的數量還這么多,它們之間的關系是怎么樣的,又是誰來管理這些上下文呢,這就不得不說說執行上下文棧了。

叁 ❀ 執行上下文棧(執行棧)

執行上下文棧(下文簡稱執行棧)也叫調用棧,執行棧用于存儲代碼執行期間創建的所有上下文,具有LIFO(Last In First Out后進先出,也就是先進后出)的特性。

JS代碼首次運行,都會先創建一個全局執行上下文并壓入到執行棧中,之后每當有函數被調用,都會創建一個新的函數執行上下文并壓入棧內;由于執行棧LIFO的特性,所以可以理解為,JS代碼執行完畢前在執行棧底部永遠有個全局執行上下文。

function f1() { f2(); console.log(1);};function f2() { f3(); console.log(2);};function f3() { console.log(3);};f1();//3 2 1

我們通過執行棧與上下文的關系來解釋上述代碼的執行過程,為了方便理解,我們假象執行棧是一個數組,在代碼執行初期一定會創建全局執行上下文并壓入棧,因此過程大致如下:

//代碼執行前創建全局執行上下文ECStack = [globalContext];// f1調用ECStack.push(’f1 functionContext’);// f1又調用了f2,f2執行完畢之前無法console 1ECStack.push(’f2 functionContext’);// f2又調用了f3,f3執行完畢之前無法console 2ECStack.push(’f3 functionContext’);// f3執行完畢,輸出3并出棧ECStack.pop();// f2執行完畢,輸出2并出棧ECStack.pop();// f1執行完畢,輸出1并出棧ECStack.pop();// 此時執行棧中只剩下一個全局執行上下文

那么到這里,我們解釋了執行棧與執行上下文的存儲規則;還記得我在前文提到代碼執行前JS引擎會做準備創建執行上下文嗎,具體怎么創建呢,我們接著說。

肆 ❀ 執行上下文創建階段

執行上下文創建分為創建階段與執行階段兩個階段,較為難理解應該是創建階段,我們先說創建階段。

JS執行上下文的創建階段主要負責三件事:確定this---創建詞法環境組件(LexicalEnvironment)---創建變量環境組件(VariableEnvironment)

這里我就直接借鑒了他人翻譯資料的偽代碼,來表示這個創建過程:

ExecutionContext = { // 確定this的值 ThisBinding = <this value>, // 創建詞法環境組件 LexicalEnvironment = {}, // 創建變量環境組件 VariableEnvironment = {},};

如果你有閱讀其它關于執行上下文的文章讀到這里一定有疑問,執行上下文創建過程不是應該解釋this,作用域與變量對象/活動對象才對嗎,怎么跟別的地方說的不一樣,這點我后面解釋。

1.確定this

官方的稱呼為This Binding,在全局執行上下文中,this總是指向全局對象,例如瀏覽器環境下this指向window對象。

而在函數執行上下文中,this的值取決于函數的調用方式,如果被一個對象調用,那么this指向這個對象。否則this一般指向全局對象window或者undefined(嚴格模式)。

2.詞法環境組件

詞法環境是一個包含標識符變量映射的結構,這里的標識符表示變量/函數的名稱,變量是對實際對象【包括函數類型對象】或原始值的引用。

詞法環境由環境記錄與對外部環境引入記錄兩個部分組成。

其中環境記錄用于存儲當前環境中的變量和函數聲明的實際位置;外部環境引入記錄很好理解,它用于保存自身環境可以訪問的其它外部環境,那么說到這個,是不是有點作用域鏈的意思?

我們在前文提到了全局執行上下文與函數執行上下文,所以這也導致了詞法環境分為全局詞法環境與函數詞法環境兩種。

全局詞法環境組件:

對外部環境的引入記錄為null,因為它本身就是最外層環境,除此之外它還記錄了當前環境下的所有屬性、方法位置。

函數詞法環境組件:

包含了用戶在函數中定義的所有屬性方法外,還包含了一個arguments對象。函數詞法環境的外部環境引入可以是全局環境,也可以是其它函數環境,這個根據實際代碼而來。

這里借用譯文中的偽代碼(環境記錄在全局和函數中也不同,全局中的環境記錄叫對象環境記錄,函數中環境記錄叫聲明性環境記錄,說多了糊涂,下方有展示):

// 全局環境GlobalExectionContext = { // 全局詞法環境 LexicalEnvironment: { // 環境記錄 EnvironmentRecord: { Type: 'Object', //類型為對象環境記錄 // 標識符綁定在這里 }, outer: < null > }};// 函數環境FunctionExectionContext = { // 函數詞法環境 LexicalEnvironment: { // 環境紀錄 EnvironmentRecord: { Type: 'Declarative', //類型為聲明性環境記錄 // 標識符綁定在這里 }, outer: < Global or outerfunction environment reference > }};

3.變量環境組件

變量環境可以說也是詞法環境,它具備詞法環境所有屬性,一樣有環境記錄與外部環境引入。在ES6中唯一的區別在于詞法環境用于存儲函數聲明與let const聲明的變量,而變量環境僅僅存儲var聲明的變量。

我們通過一串偽代碼來理解它們:

let a = 20; const b = 30; var c;function multiply(e, f) { var g = 20; return e * f * g; }c = multiply(20, 30);

我們用偽代碼來描述上述代碼中執行上下文的創建過程:

//全局執行上下文GlobalExectionContext = { // this綁定為全局對象 ThisBinding: <Global Object>, // 詞法環境 LexicalEnvironment: { //環境記錄 EnvironmentRecord: { Type: 'Object', // 對象環境記錄 // 標識符綁定在這里 let const創建的變量a b在這 a: < uninitialized >, b: < uninitialized >, multiply: < func > } // 全局環境外部環境引入為null outer: <null> }, VariableEnvironment: { EnvironmentRecord: { Type: 'Object', // 對象環境記錄 // 標識符綁定在這里 var創建的c在這 c: undefined, } // 全局環境外部環境引入為null outer: <null> } } // 函數執行上下文 FunctionExectionContext = { //由于函數是默認調用 this綁定同樣是全局對象 ThisBinding: <Global Object>, // 詞法環境 LexicalEnvironment: { EnvironmentRecord: { Type: 'Declarative', // 聲明性環境記錄 // 標識符綁定在這里 arguments對象在這 Arguments: {0: 20, 1: 30, length: 2}, }, // 外部環境引入記錄為</Global> outer: <GlobalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: 'Declarative', // 聲明性環境記錄 // 標識符綁定在這里 var創建的g在這 g: undefined }, // 外部環境引入記錄為</Global> outer: <GlobalEnvironment> } }

不知道你有沒有發現,在執行上下文創建階段,函數聲明與var聲明的變量在創建階段已經被賦予了一個值,var聲明被設置為了undefined,函數被設置為了自身函數,而let const被設置為未初始化。

現在你總知道變量提升與函數聲明提前是怎么回事了吧,以及為什么let const為什么有暫時性死域,這是因為作用域創建階段JS引擎對兩者初始化賦值不同。

上下文除了創建階段外,還有執行階段,這點大家應該好理解,代碼執行時根據之前的環境記錄對應賦值,比如早期var在創建階段為undefined,如果有值就對應賦值,像let const值為未初始化,如果有值就賦值,無值則賦予undefined。

伍 ❀ 關于變量對象與活動對象

回答前面的問題,為什么別人的博文介紹上下文都是談作用域,變量對象和活動對象,我這就成了詞法環境,變量環境了。

我在閱讀相關資料也產生了這個疑問,一番查閱可以確定的是,變量對象與活動對象的概念是ES3提出的老概念,從ES5開始就用詞法環境和變量環境替代了,因為更好解釋。

在上文中,我們通過介紹詞法環境與變量環境解釋了為什么var會存在變量提升,為什么let const沒有,而通過變量對象與活動對象是很難解釋的,由其是在JavaScript在更新中不斷在彌補當初設計的坑。

其次,詞法環境的概念與變量對象這類概念也是可以對應上的。

我們知道變量對象與活動對象其實都是變量對象,變量對象是與執行上下文相關的數據作用域,存儲了在上下文中定義的變量和函數聲明。而在函數上下文中,我們用活動對象(activation object, AO)來表示變量對象。

那這不正好對應到了全局詞法記錄與函數詞法記錄了嗎。而且由于ES6新增的let const不存在變量提升,于是正好有了詞法環境與變量環境的概念來解釋這個問題。

所以說到這,你也不用為詞法環境,變量對象的概念鬧沖突了。

我們來總結下上面提到的概念。

陸 ❀ 總結

1.全局執行上下文一般由瀏覽器創建,代碼執行時就會創建;函數執行上下文只有函數被調用時才會創建,調用多少次函數就會創建多少上下文。

2.調用棧用于存放所有執行上下文,滿足FILO規則。

3.執行上下文創建階段分為綁定this,創建詞法環境,變量環境三步,兩者區別在于詞法環境存放函數聲明與const let聲明的變量,而變量環境只存儲var聲明的變量。

4.詞法環境主要由環境記錄與外部環境引入記錄兩個部分組成,全局上下文與函數上下文的外部環境引入記錄不一樣,全局為null,函數為全局環境或者其它函數環境。環境記錄也不一樣,全局叫對象環境記錄,函數叫聲明性環境記錄。

5.你應該明白了為什么會存在變量提升,函數提升,而let const沒有。

6.ES3之前的變量對象與活動對象的概念在ES5之后由詞法環境,變量環境來解釋,兩者概念不沖突,后者理解更為通俗易懂。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網。

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩精品乱码av一区二区| 午夜欧美视频| 免费高潮视频95在线观看网站| 成人日韩在线观看| 成人三级高清视频在线看| 九九99久久精品在免费线bt| 久久国产人妖系列| 99国产精品| 99国产精品久久久久久久| 狠狠干成人综合网| 日韩视频久久| 国产农村妇女精品一区二区| 久久99伊人| 亚洲少妇一区| 亚洲精选成人| 日韩av一区二| 国产精品日本一区二区不卡视频| 国产精品久av福利在线观看| 麻豆成人av在线| 国产成人精品一区二区免费看京 | 欧美一区91| 日韩高清在线不卡| 亚洲综合中文| 免费看日韩精品| 亚洲91在线| 欧美片第1页综合| 美女毛片一区二区三区四区最新中文字幕亚洲 | 好看的亚洲午夜视频在线| 99在线精品视频在线观看| 免费不卡在线观看| 国产精品黄网站| 亚洲三级欧美| 欧美大黑bbbbbbbbb在线| 一级欧美视频| 久久99久久久精品欧美| 欧美一区久久久| 亚洲在线一区| 国产精品嫩模av在线| 日本蜜桃在线观看视频| 亚洲专区欧美专区| 日韩激情视频网站| 久久精品国产成人一区二区三区| 欧美丰满日韩| 夜夜嗨网站十八久久| 一区二区不卡| 国精品产品一区| 日韩午夜精品| 国产精品久久亚洲不卡| av高清一区| 亚州欧美在线| 成人亚洲一区| 日韩影院免费视频| 国产精品99久久免费| 136国产福利精品导航网址| 亚洲在线网站| 欧美精品影院| 日本高清不卡一区二区三区视频| 亚洲一区国产一区| 麻豆成人av在线| 午夜一区在线| 国产精品香蕉| 精品中文一区| 国产精品亚洲综合色区韩国| 亚洲一级少妇| 日韩国产欧美三级| 日韩av福利| 欧美另类中文字幕| 亚洲午夜电影| 国产极品嫩模在线观看91精品| 久久一区二区三区喷水| 中文一区一区三区免费在线观 | 18国产精品| 精品视频97| 亚洲视频二区| 91精品韩国| 国产欧美另类| 午夜国产精品视频| 精品九九久久| 日本不卡视频在线| 国产一区日韩一区| 久久三级中文| 亚洲美女久久| 99成人在线视频| 国产美女精品视频免费播放软件| 伊人久久大香线蕉av不卡| 国产欧美日韩在线观看视频 | 999精品在线| 欧美极品中文字幕| 免费观看久久久4p| 欧美色图国产精品| 欧美精品99| 亚洲一区二区小说| 宅男在线一区| 国产在线不卡一区二区三区| 日本亚洲最大的色成网站www | 美女日韩在线中文字幕| 国产传媒av在线| 7m精品国产导航在线| 香蕉久久久久久久av网站| 亚洲精品一级二级| 成人精品国产亚洲| 久久精品 人人爱| 丝袜美腿高跟呻吟高潮一区| 在线中文字幕播放| 国产精品入口久久| 亚洲1区在线观看| 亚洲一区久久| 日本精品不卡| 久久久久免费| 精品视频一区二区三区四区五区| 日本亚洲视频| 久久高清免费观看| 青青久久av| 亚洲国产福利| 成人污污视频| 久久av网址| 国产图片一区| 日日摸夜夜添夜夜添国产精品| 欧美精选一区二区三区| 久久人人97超碰国产公开结果| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 精品久久电影| 麻豆中文一区二区| 国产精品中文| 日韩不卡一区二区三区| 蜜桃视频在线观看一区二区| 久久久久欧美精品| 精品视频自拍| 欧美亚洲色图校园春色| 麻豆成人在线| 亚洲精品综合| 中文字幕亚洲精品乱码| 视频一区欧美精品| 国产精品腿扒开做爽爽爽挤奶网站| 美女视频网站久久| 国产成人精品一区二区三区视频| 精品午夜视频| 成人台湾亚洲精品一区二区 | 日本va欧美va精品发布| 日韩一区二区三区在线看| 国产亚洲永久域名| 午夜在线一区| 三级久久三级久久久| 青青青国产精品| 国产精品久久久久久久久久白浆 | 亚洲欧美日本日韩| 美女日韩在线中文字幕| 亚洲精品一二三**| 国产另类在线| 欧美大黑bbbbbbbbb在线| 91欧美在线| 日韩精品成人在线观看| 亚洲精品成人| 蜜桃一区二区三区在线观看| 日韩精品首页| 国产精品.xx视频.xxtv| 欧美日韩在线二区| 欧洲av一区二区| 精品国产精品久久一区免费式 | 九九99久久精品在免费线bt| 国产精品亲子伦av一区二区三区 | 另类专区亚洲| 激情综合自拍| 性一交一乱一区二区洋洋av| 日韩精品一区二区三区中文字幕| 国产探花在线精品| a国产在线视频| 欧美日韩国产高清电影| 亚洲精品在线二区| 国产精品一区二区三区av | 欧美日韩在线观看首页| 欧洲激情综合| 国产精品66| 亚洲久久视频| 国产一卡不卡| 日韩精品免费视频人成| 男人的天堂久久精品| 国产欧美日韩影院| 四季av一区二区凹凸精品| 99精品美女| 中文字幕av一区二区三区人| 国产精品主播| 午夜av成人| 亚洲免费中文| 日韩精品高清不卡| 国产成人精品亚洲线观看| 国产在线日韩| 日本天堂一区| 麻豆视频在线看| 亚洲一区二区三区四区五区午夜| 国产精品一二| 免费精品国产的网站免费观看| 亚州精品视频| 亚洲一区资源| 中文字幕av亚洲精品一部二部| 麻豆精品久久| 免费在线观看一区二区三区| 久久香蕉网站| 男女性色大片免费观看一区二区| 久久精品99国产精品|