第二章:重點(diǎn)
詞法作用域意味著作用域是由書寫代碼時(shí)函數(shù)聲明的位置來決定的。編譯的詞法分析階段 基本能夠知道全部標(biāo)識符在哪里以及是如何聲明的,從而能夠預(yù)測在執(zhí)行過程中如何對它 們進(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è)對象。其中一個(gè)具有 a 屬性,另外一個(gè)沒有。foo(..) 函 數(shù)接受一個(gè)obj參數(shù),該參數(shù)是一個(gè)對象引用,并對這個(gè)對象引用執(zhí)行了with(obj) {..}。
在 with 塊內(nèi)部,我們寫的代碼看起來只是對變量 a 進(jì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 并沒有 a 屬性,因此不會(huì)創(chuàng)建這個(gè)屬性, o2.a 保持 undefined。
eval(..) 函數(shù)如果接受了含有一個(gè)或多個(gè)聲明的代碼,就會(huì)修改其所處的詞法作用域,而 with 聲明實(shí)際上是根據(jù)你傳遞給它的對象憑空創(chuàng)建了一個(gè)全新的詞法作用域。
可以這樣理解,當(dāng)我們傳遞 o1 給 with 時(shí),with 所聲明的作用域是 o1,而這個(gè)作用域中含 有一個(gè)同 o1.a 屬性相符的標(biāo)識符。但當(dāng)我們將 o2 作為作用域時(shí),其中并沒有 a 標(biāo)識符, 因此進(jìn)行了正常的 LHS 標(biāo)識符查找(查看第 1 章)。
o2 的作用域、foo(..) 的作用域和全局作用域中都沒有找到標(biāo)識符 a,因此當(dāng) a=2 執(zhí)行 時(shí),自動(dòng)創(chuàng)建了一個(gè)全局變量(因?yàn)槭欠菄?yán)格模式)。
with 這種將對象及其屬性放進(jìn)一個(gè)作用域并同時(shí)分配標(biāo)識符的行為很讓人費(fèi)解。但為了說 明我們所看到的現(xiàn)象,這是我能給出的最直白的解釋了。