摘要:全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)變量對(duì)象。綜上,每個(gè)函數(shù)對(duì)應(yīng)一個(gè)執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境對(duì)應(yīng)一個(gè)變量對(duì)象,而多個(gè)變量對(duì)象構(gòu)成了作用域鏈,如果當(dāng)前執(zhí)行環(huán)境是函數(shù),那么其活動(dòng)對(duì)象在作用域鏈的前端。
1.幾個(gè)概念
先說幾個(gè)概念:函數(shù)、執(zhí)行環(huán)境、變量對(duì)象、作用域鏈、活動(dòng)對(duì)象。這幾個(gè)東東之間有什么關(guān)系呢,往下看~
函數(shù)函數(shù)大家都知道,我想說的是,js中,在函數(shù)內(nèi)部有兩個(gè)特殊的對(duì)象:arguments 和 this 。 arguments 是一個(gè)類數(shù)組對(duì)象,包含著傳入函數(shù)中的所有參數(shù)。 this 引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對(duì)象。
執(zhí)行環(huán)境在《js高級(jí)程序設(shè)計(jì)》中,是這樣定義的:
執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了它們各自的行為。
這里要特別提到一個(gè)執(zhí)行環(huán)境——全局執(zhí)行環(huán)境。全局執(zhí)行環(huán)境是最外圍的執(zhí)行環(huán)境,在web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是window對(duì)象。全局執(zhí)行環(huán)境會(huì)一直存在于環(huán)境棧的最底端,直到關(guān)閉網(wǎng)頁或者瀏覽器。
執(zhí)行環(huán)境也叫執(zhí)行上下文。
《js高級(jí)程序設(shè)計(jì)》定義如下:
每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。
由上可以看出兩點(diǎn):1.執(zhí)行環(huán)境和變量對(duì)象是一一對(duì)應(yīng)的。2.執(zhí)行環(huán)境其實(shí)是一個(gè)“虛”的概念,而變量對(duì)象是實(shí)際存在的對(duì)象,能夠被解析器訪問到。不嚴(yán)謹(jǐn)?shù)恼f,為了訪問執(zhí)行環(huán)境,就創(chuàng)造了變量對(duì)象這個(gè)東東,通過變量對(duì)象就可以訪問執(zhí)行環(huán)境中的所有變量和函數(shù)了,它倆其實(shí)是一個(gè)東西,只不過一個(gè)是虛的,一個(gè)是真實(shí)存在的。
當(dāng)一個(gè)執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢后,該執(zhí)行環(huán)境被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀。其實(shí)是這個(gè)執(zhí)行環(huán)境對(duì)應(yīng)的變量對(duì)象被銷毀。發(fā)現(xiàn)很多地方都把執(zhí)行環(huán)境和變量對(duì)象混談,大家似乎很少提到變量對(duì)象,都用 “執(zhí)行環(huán)境” 這四個(gè)字替代了,把執(zhí)行環(huán)境說成了一個(gè)對(duì)象,沒辦法,誰讓說的是一個(gè)東西呢。
變量對(duì)象補(bǔ)充當(dāng)JS執(zhí)行流進(jìn)入函數(shù)時(shí),JavaScript引擎在內(nèi)部創(chuàng)建一個(gè)對(duì)象,叫做Variable Object。
對(duì)應(yīng)函數(shù)的每一個(gè)參數(shù),在Variable Object上添加一個(gè)屬性,屬性的名字、值與參數(shù)的名字、值相同。
函數(shù)中每聲明一個(gè)變量,也會(huì)在Variable Object上添加一個(gè)屬性,名字就是變量名,因此為變量賦值就是給Variable Object對(duì)應(yīng)的屬性賦值。
在函數(shù)中訪問參數(shù)或者局部變量時(shí),就是在variable Object上搜索相應(yīng)的屬性,返回其值。
一般情況下Variable Object是一個(gè)內(nèi)部對(duì)象,JS代碼中無法直接訪問。
作用域鏈的用途:保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的 有序 訪問。
當(dāng)代碼在一個(gè)執(zhí)行環(huán)境中執(zhí)行時(shí),就會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。
我的理解是,作用域鏈?zhǔn)怯梢粋€(gè)一個(gè)變量對(duì)象鏈接起來的一個(gè)鏈,整個(gè)作用域鏈構(gòu)成了當(dāng)前執(zhí)行環(huán)境中變量和函數(shù)可訪問的范圍,即作用域。由于變量對(duì)象是按一定順序鏈接在一起的,所以就達(dá)到了對(duì)所有可訪問變量、函數(shù)有序訪問的效果。那么它們是按怎樣的順序鏈接成作用域鏈的呢?這就要說到最后一個(gè)概念——活動(dòng)對(duì)象。
活動(dòng)對(duì)象當(dāng)函數(shù)運(yùn)行時(shí)就會(huì)為其創(chuàng)建一個(gè)活動(dòng)對(duì)象,其中包含形參和函數(shù)特殊的arguments對(duì)象?;顒?dòng)對(duì)象之后會(huì)做為函數(shù)執(zhí)行環(huán)境的變量對(duì)象來使用。
回到之前的問題,作用域鏈中的變量對(duì)象是如何排序的呢?
作用域鏈的前端,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對(duì)象。但如果這個(gè)環(huán)境是函數(shù),則將其活動(dòng)對(duì)象作為變量對(duì)象,放在其作用域鏈的前端。作用域鏈中的下一個(gè)變量對(duì)象來自包含環(huán)境,而再下一個(gè)變量對(duì)象來自下一個(gè)包含環(huán)境……這樣一直延續(xù)到全局執(zhí)行環(huán)境。全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)變量對(duì)象。
為什么執(zhí)行環(huán)境是函數(shù)會(huì)有這樣特殊的規(guī)定呢?
《JS權(quán)威指南》中有一句很精辟的描述:
JavaScript中的函數(shù)運(yùn)行在它們被定義的作用域里,而不是它們被執(zhí)行的作用域里。
按照之前所說,在函數(shù)定義的作用域里,當(dāng)前執(zhí)行環(huán)境的作用域鏈上是沒有該函數(shù)的活動(dòng)對(duì)象的,為了訪問函數(shù)內(nèi)部的變量、函數(shù),所以要將其活動(dòng)對(duì)象插在當(dāng)前作用域鏈的前端。
2.它們之間的關(guān)系每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境,當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中。而在執(zhí)行后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。
綜上,每個(gè)函數(shù)對(duì)應(yīng)一個(gè)執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境對(duì)應(yīng)一個(gè)變量對(duì)象,而多個(gè)變量對(duì)象構(gòu)成了作用域鏈,如果當(dāng)前執(zhí)行環(huán)境是函數(shù),那么其活動(dòng)對(duì)象在作用域鏈的前端。
3.其他補(bǔ)充JS的語法風(fēng)格和 C/C++ 類似, 但作用域的實(shí)現(xiàn)卻和 C/C++ 不同,并非用“堆?!狈绞?,而是使用列表,具體過程如下(ECMA262中所述):
任何執(zhí)行上下文時(shí)刻的作用域, 都是由作用域鏈(scope chain)來實(shí)現(xiàn).
在執(zhí)行func的定義語句的時(shí)候, 會(huì)創(chuàng)建一個(gè)這個(gè)函數(shù)對(duì)象的[[scope]]屬性(內(nèi)部屬性,只有JS引擎可以訪問),并將這個(gè)[[scope]]屬性鏈接到定義它的作用域鏈上。
在調(diào)用func的時(shí)候, 會(huì)創(chuàng)建一個(gè)活動(dòng)對(duì)象,然后將調(diào)用參數(shù)賦值給形參數(shù),對(duì)于缺少的調(diào)用參數(shù),賦值為undefined。然后將這個(gè)活動(dòng)對(duì)象做為scope chain的最前端, 并將func的[[scope]]屬性所指向的,定義func時(shí)候的頂級(jí)活動(dòng)對(duì)象,加入到scope chain.
《js高級(jí)程序設(shè)計(jì)》 P73 4.2 執(zhí)行環(huán)境及作用域
鳥哥:JavaScript作用域原理
JavaScript 開發(fā)進(jìn)階:理解 JavaScript 作用域和作用域鏈
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/91506.html
摘要:閉包是怎么通過作用域鏈霸占更多內(nèi)存的本文是作者學(xué)習(xí)高級(jí)程序設(shè)計(jì)第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)參考原教材。函數(shù)執(zhí)行過程創(chuàng)建了一個(gè)函數(shù)的活動(dòng)對(duì)象,作用域鏈的最前端指向這個(gè)對(duì)象。函數(shù)執(zhí)行完畢返回值后執(zhí)行環(huán)境作用域鏈和活動(dòng)對(duì)象一并銷毀。 JavaScript 閉包是怎么通過作用域鏈霸占更多內(nèi)存的? 本文是作者學(xué)習(xí)《JavaScript 高級(jí)程序設(shè)計(jì)》7.2第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)...
摘要:關(guān)于作用域?qū)崿F(xiàn)的描述任何執(zhí)行上下文時(shí)刻的作用域,都是由作用域鏈來實(shí)現(xiàn)的。在一個(gè)函數(shù)被定義的時(shí)候,會(huì)將它此時(shí)的作用域鏈鏈接到這個(gè)函數(shù)對(duì)象的屬性。參考資料鳥哥作用域原理理解作用域和作用域鏈阮一峰老師微博上的關(guān)于作用域的一道題 javascript作用域原理學(xué)習(xí) 在每次調(diào)用一個(gè)函數(shù)的時(shí)候,就會(huì)進(jìn)入一個(gè)函數(shù)內(nèi)的作用域,當(dāng)從函數(shù)返回 以后,就會(huì)返回調(diào)用前的作用域。 ECMA262關(guān)于作...
摘要:但是,必須強(qiáng)調(diào),閉包是一個(gè)運(yùn)行期概念。通過原型鏈可以實(shí)現(xiàn)繼承,而與閉包相關(guān)的就是作用域鏈。常理來說,一個(gè)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀。所以此時(shí),的作用域鏈雖然銷毀了,但是其活動(dòng)對(duì)象仍在內(nèi)存中。 學(xué)習(xí)Javascript閉包(Closure)javascript的閉包JavaScript 閉包深入理解(closure)理解 Javascript 的閉包JavaScript ...
摘要:每一個(gè)運(yùn)行期上下文都和一個(gè)作用域鏈關(guān)聯(lián)。這個(gè)對(duì)象將被推入作用域鏈的頭部,這意味著函數(shù)的所有局部變量現(xiàn)在處于第二個(gè)作用域鏈對(duì)象中,因此訪問代價(jià)更高了。在代碼塊內(nèi)部,函數(shù)的所有局部變量將會(huì)被放在第二個(gè)作用域鏈對(duì)象中。 參考: Javascript作用域原理 理解 JavaScript 作用域和作用域鏈 JavaScript 作用域 作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)...
摘要:我們?cè)賮砜匆幌碌谝欢未a小紅小黑腳本出錯(cuò)腳本出錯(cuò)在這段代碼中變量與函數(shù),都擁有局部作用域。作用域鏈的最前端,始終都是當(dāng)前執(zhí)行代碼所在的作用域的變量對(duì)象。 個(gè)人博客原址 無論什么語言中,作用域都是一個(gè)十分重要的概念,在JavaScript中也不例外,作用域定義了變量或者函數(shù)有權(quán)訪問的范圍,決定了它們各自的行為。要理解JavaScript中的作用域首先就要知道:在let出現(xiàn)之前,JS中變...
閱讀 3362·2021-11-24 09:38
閱讀 2241·2021-11-23 09:51
閱讀 1895·2021-10-13 09:39
閱讀 2702·2021-09-23 11:53
閱讀 1500·2021-09-02 15:40
閱讀 3727·2019-08-30 15:54
閱讀 1197·2019-08-30 13:04
閱讀 2651·2019-08-30 11:01