1.什么是詞法作用域?
詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域是由你在寫代碼時將變量和塊作用域寫在哪里來決定的,因此當詞法分析器處理代碼時會保持作用域不變 。
2.欺騙詞法
怎么在才能在運行中 “修改”詞法作用域呢??
答案:JavaScript中有兩種機制實現這個目的,不過值得注意的是欺騙詞法作用域會導致性能下降
兩種機制如下
1.eval() 函數 ---魔鬼
函數可以接受一個字符串為參數,這個字符相當於可以運行的JavaScript代碼,在執行eval之后,引擎並不知道eval是以動態的方式進入的,並對詞法環境進行修改。
function foo(str, a) { eval( str ); // 欺騙! console.log( a, b ); } var b = 2; foo( "var b = 3;", 1 ); // 1, 3
在執行eval之后,var b = 2; 會生成一個詞法環境,即在foo作用域里面定義了b變量,console.log訪問時首先會在自己的詞法作用域里尋找a,b變量。類似的有setTimeout(),setInterval();
3.with()
with通常被當作重復引用同一個對象中的多個屬性的快捷方式,可以不需要重復引用對象本身。
var obj = { a: 1, b: 2, c: 3 }; // 單調乏味的重復"obj" obj.a = 2; obj.b = 3; obj.c = 4; // 簡單的快捷方式 with (obj) { a = 3; b = 4; c = 5; }
3.性能
JavaScript引擎會在編譯階段進行數項的性能優化。其中有些優化依賴於能夠根據代碼的詞行靜態分析,並預先確定所有變量和函數的定義位置,才能在執行過程中快速找到標識符 。如果引擎在代碼中發現了eval(..)或with.
它只能簡單地假設關於標識符位置的判斷都是無效的,因為無法在詞法分析階段明確知道eval(..)會接收到什么代碼,這些代碼會如何對作用域進行修改,也無法知道傳遞給with用來創建新詞法作用域的對象的內容到底是什么。