作用域鏈
我們看下面這段代碼:
function compare(value1, value2){
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
}
var result = compare(5, 10);
以上代碼先定義了compare()函數(shù)晋修,然后又在全局作用域中調(diào)用了它。當(dāng)調(diào)用compare()時(shí),會(huì)創(chuàng)建一個(gè)包含arguments秸仙、value1 和value2 的活動(dòng)對(duì)象。全局執(zhí)行環(huán)境的變量對(duì)象(包含result和compare)在compare()執(zhí)行環(huán)境的作用域鏈中則處于第二位桩盲。下圖展示了包含上述關(guān)系的compare()函數(shù)執(zhí)行時(shí)的作用域鏈寂纪。
后臺(tái)的每個(gè)執(zhí)行環(huán)境都有一個(gè)表示變量的對(duì)象——變量對(duì)象。全局環(huán)境的變量對(duì)象始終存在赌结,而像compare()函數(shù)這樣的局部環(huán)境的變量對(duì)象捞蛋,則只在函數(shù)執(zhí)行的過(guò)程中存在。在創(chuàng)建compare()函數(shù)時(shí)柬姚,會(huì)創(chuàng)建一個(gè)預(yù)先包含全局變量對(duì)象的作用域鏈拟杉,這個(gè)作用域鏈被保存在內(nèi)部的[[Scope]]屬性中。
當(dāng)調(diào)用compare()函數(shù)時(shí)量承,會(huì)為函數(shù)創(chuàng)建一個(gè)執(zhí)行環(huán)境搬设,然后通過(guò)復(fù)制函數(shù)的[[Scope]]屬性中的對(duì)象構(gòu)建起執(zhí)行環(huán)境的作用域鏈。此后撕捍,又有一個(gè)活動(dòng)對(duì)象(在此作為變量對(duì)象使用)被創(chuàng)建并被推入執(zhí)行環(huán)境作用域鏈的前端拿穴。對(duì)于這個(gè)例子中compare()函數(shù)的執(zhí)行環(huán)境而言,其作用域鏈中包含兩個(gè)變量對(duì)象:本地活動(dòng)對(duì)象和全局變量對(duì)象忧风。
顯然默色,作用域鏈本質(zhì)上是一個(gè)指向變量對(duì)象的指針列表,它只引用但不實(shí)際包含變量對(duì)象狮腿。
無(wú)論什么時(shí)候在函數(shù)中訪問(wèn)一個(gè)變量時(shí)腿宰,就會(huì)從作用域鏈中搜索具有相應(yīng)名字的變量呕诉。一般來(lái)講,當(dāng)函數(shù)執(zhí)行完畢后吃度,局部活動(dòng)對(duì)象就會(huì)被銷毀甩挫,內(nèi)存中僅保存全局作用域(全局執(zhí)行環(huán)境的變量對(duì)象)。但是规肴,閉包的情況又有所不同捶闸。
function createComparisonFunction(propertyName) {
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
在另一個(gè)函數(shù)內(nèi)部定義的函數(shù)會(huì)將包含函數(shù)(即外部函數(shù))的活動(dòng)對(duì)象添加到它的作用域鏈中。因此拖刃,在createComparisonFunction()函數(shù)內(nèi)部定義的匿名函數(shù)的作用域鏈中删壮,實(shí)際上將會(huì)包含外部函數(shù)createComparisonFunction()的活動(dòng)對(duì)象。這段代碼的作用域鏈如下所示
在匿名函數(shù)從createComparisonFunction()中被返回后兑牡,它的作用域鏈被初始化為包含createComparisonFunction()函數(shù)的活動(dòng)對(duì)象和全局變量對(duì)象央碟。這樣,匿名函數(shù)就可以訪問(wèn)在createComparisonFunction()中定義的所有變量均函。更為重要的是亿虽,createComparisonFunction()函數(shù)在執(zhí)行完畢后,其活動(dòng)對(duì)象也不會(huì)被銷毀苞也,因?yàn)槟涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對(duì)象洛勉。換句話說(shuō),當(dāng)createComparisonFunction()函數(shù)返回后如迟,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀收毫,但它的活動(dòng)對(duì)象仍然會(huì)留在內(nèi)存中;直到匿名函數(shù)被銷毀后殷勘,createComparisonFunction()的活動(dòng)對(duì)象才會(huì)被銷毀此再,例如:
//創(chuàng)建函數(shù)
var compareNames = createComparisonFunction("name");
//調(diào)用函數(shù)
var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
//解除對(duì)匿名函數(shù)的引用(以便釋放內(nèi)存)
compareNames = null;
首先,創(chuàng)建的比較函數(shù)被保存在變量compareNames 中玲销。而通過(guò)將compareNames 設(shè)置為等于null解除該函數(shù)的引用输拇,就等于通知垃圾回收例程將其清除。隨著匿名函數(shù)的作用域鏈被銷毀贤斜,其他作用域(除了全局作用域)也都可以安全地銷毀了策吠。