[[scope]]:
每個(gè)JavaScript函數(shù)都是一個(gè)對(duì)象,對(duì)象中有些屬性我們可以訪問,有些不可以,這些屬性僅供JavaScript引擎存取,[[scope]]就是其中一個(gè)。
[[scope]]指我們所說的作用域,其中存儲(chǔ)了執(zhí)行期上下文的集合。
執(zhí)行期上下文:當(dāng)函數(shù)執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)稱為執(zhí)行期上下文的內(nèi)部對(duì)象。一個(gè)執(zhí)行期上下文定義了一個(gè)函數(shù)執(zhí)行時(shí)的環(huán)境,函數(shù)每次執(zhí)行時(shí)對(duì)應(yīng)的執(zhí)行上下文都是獨(dú)一無二的,所以多次調(diào)用一個(gè)函數(shù)會(huì)導(dǎo)致創(chuàng)建多個(gè)執(zhí)行上下文,當(dāng)函數(shù)執(zhí)行完畢,它所產(chǎn)生的執(zhí)行上下文被銷毀。
作用域鏈:
[[scope]]中所存儲(chǔ)的執(zhí)行期上下文對(duì)象的集合,這個(gè)集合呈鏈?zhǔn)芥溄樱覀儼堰@種鏈?zhǔn)芥溄咏凶鲎饔糜蜴湣?br> 當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。作用域鏈的用途,是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對(duì)象。
function a() {
function b() {
var bb = 234
}
var aa = 123
b()
}
var glob = 100
a()
對(duì)這樣一段代碼 作用域鏈的過程如下:
函數(shù)b執(zhí)行完成之后,刪除作用域鏈的第一個(gè)AO,回到剛被定義的狀態(tài),等待下次執(zhí)行,下次執(zhí)行時(shí),重新創(chuàng)建一個(gè)新的AO
同理,函數(shù)a執(zhí)行完成之后,也刪除其第一個(gè)AO,回到剛被定義的狀態(tài),此時(shí)b函數(shù)直接沒有了,等到下次a函數(shù)執(zhí)行,重新創(chuàng)建一個(gè)新的AO,即又創(chuàng)建了一個(gè)新的函數(shù)b
函數(shù)b被定義的時(shí)候,作用域鏈的第一個(gè)AO,就是函數(shù)a執(zhí)行時(shí)候作用域鏈的第一個(gè)AO,如下圖所示:
也就是 這個(gè)過程:
所以,搞清楚作用域鏈之后我們知道:
內(nèi)部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境不能訪問內(nèi)部環(huán)境中的任何變量和函數(shù)。這些環(huán)境之間的聯(lián)系是線性,有次序的。每個(gè)環(huán)境都可以沿著作用域鏈向上搜索,以查詢變量和函數(shù)名;但任何環(huán)境都不能通過向下搜索作用域鏈而進(jìn)入另一個(gè)執(zhí)行環(huán)境。搜索過程是從作用域鏈的頂端開始,逐級(jí)的向后回溯,直至找到要找的變量或函數(shù)名為止。
實(shí)際上閉包的實(shí)現(xiàn)是這樣的:
可以先看我作用域及作用域鏈這節(jié)
對(duì)這段代碼,
a執(zhí)行,然后定義了b,并把b給保存出來
然后a執(zhí)行結(jié)束,把作用域鏈的第0位刪除,但此時(shí)a的AO沒有被垃圾回收,因?yàn)檫€有b的作用域鏈引用著它,如下圖所示。
所以b被保存到外部之后,還可對(duì)a中的AO進(jìn)行操作,即還可以訪問函數(shù)a里的變量aaa,所以執(zhí)行demo后,能打印出aaa,也可對(duì)aaa進(jìn)行操作。