第二章:重點(diǎn)
詞法作用域意味著作用域是由書(shū)寫(xiě)代碼時(shí)函數(shù)聲明的位置來(lái)決定的。編譯的詞法分析階段 基本能夠知道全部標(biāo)識(shí)符在哪里以及是如何聲明的,從而能夠預(yù)測(cè)在執(zhí)行過(guò)程中如何對(duì)它 們進(jìn)行查找丸相。
function foo(obj) { with (obj) {
a = 2; }
}
var o1 = { a: 3
};
var o2 = { b: 3
};
foo( o1 );
console.log( o1.a ); // 2
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!
這個(gè)例子中創(chuàng)建了 o1 和 o2 兩個(gè)對(duì)象俯在。其中一個(gè)具有 a 屬性,另外一個(gè)沒(méi)有竟秫。foo(..) 函 數(shù)接受一個(gè)obj參數(shù),該參數(shù)是一個(gè)對(duì)象引用,并對(duì)這個(gè)對(duì)象引用執(zhí)行了with(obj) {..}。
在 with 塊內(nèi)部,我們寫(xiě)的代碼看起來(lái)只是對(duì)變量 a 進(jìn)行簡(jiǎn)單的詞法引用,實(shí)際上就是一個(gè) LHS 引用(查看第 1 章),并將 2 賦值給它跷乐。
當(dāng)我們將 o1 傳遞進(jìn)去,a=2 賦值操作找到了 o1.a 并將 2 賦值給它,這在后面的 console. log(o1.a) 中可以體現(xiàn)肥败。而當(dāng) o2 傳遞進(jìn)去,o2 并沒(méi)有 a 屬性,因此不會(huì)創(chuàng)建這個(gè)屬性, o2.a 保持 undefined。
eval(..) 函數(shù)如果接受了含有一個(gè)或多個(gè)聲明的代碼,就會(huì)修改其所處的詞法作用域,而 with 聲明實(shí)際上是根據(jù)你傳遞給它的對(duì)象憑空創(chuàng)建了一個(gè)全新的詞法作用域愕提。
可以這樣理解,當(dāng)我們傳遞 o1 給 with 時(shí),with 所聲明的作用域是 o1,而這個(gè)作用域中含 有一個(gè)同 o1.a 屬性相符的標(biāo)識(shí)符馒稍。但當(dāng)我們將 o2 作為作用域時(shí),其中并沒(méi)有 a 標(biāo)識(shí)符, 因此進(jìn)行了正常的 LHS 標(biāo)識(shí)符查找(查看第 1 章)。
o2 的作用域浅侨、foo(..) 的作用域和全局作用域中都沒(méi)有找到標(biāo)識(shí)符 a,因此當(dāng) a=2 執(zhí)行 時(shí),自動(dòng)創(chuàng)建了一個(gè)全局變量(因?yàn)槭欠菄?yán)格模式)纽谒。
with 這種將對(duì)象及其屬性放進(jìn)一個(gè)作用域并同時(shí)分配標(biāo)識(shí)符的行為很讓人費(fèi)解。但為了說(shuō) 明我們所看到的現(xiàn)象,這是我能給出的最直白的解釋了如输。