這個(gè)話題涉及面很大,通過學(xué)習(xí),不斷補(bǔ)充。
- 非嚴(yán)格模式,瀏覽器在此模式下表現(xiàn)會有一些不同,主要體現(xiàn)在:
- 變量不需要聲明就能直接賦值;
- 作用域也會有些許不同;
- 可以使用某些函數(shù),如:eval,with,setTimeout,setInterval,new Function(..);
- 嚴(yán)格模式,瀏覽器會遵照我們一般開發(fā)習(xí)俗(使用前需聲明:"use strict"):
- 變量使用前必需聲明;
- 嚴(yán)格限制在作用域中;
- 不允許使用with,eval有自己的作用域;
對于1、2(如下代碼):
// 非嚴(yán)格模式
function foo(a) {
b = a; // b = 2; 且此時(shí) b為全局變量
}
// 嚴(yán)格模式
function foo(a) {
"use strict";
b = a; // ReferenceError: b is not defined
}
foo(2);
對于3(如下代碼):
// eval使用
function foo(str, a) {
eval(str);
console.log(a, b); // 2, 3
}
function foo(str, a) {
"use strict";
eval(str);
console.log(a, b); // ReferenceError: b is not defined
}
var b = 1;
foo("var b = 3", 2);
/**
* JavaScript 中的 eval(..) 函數(shù)可以接受一個(gè)字符串為參數(shù),
* 并將其中的內(nèi)容視為好像在書寫時(shí)就存在于程序中這個(gè)位置的代碼。
* 換句話說,可以在你寫的代碼中用程序生成代碼并運(yùn)行,就好像代
* 碼是寫在那個(gè)位置的一樣!
*
* 如上代碼,由于動態(tài)語句中在foo函數(shù)中通過eval執(zhí)行后,在foo
* 函數(shù)中聲明了一個(gè)變量b且賦值為3,RHS查詢b時(shí),由于在foo函數(shù)
* 中已經(jīng)找到了變量b(就近原則),因此改變了log的結(jié)果。
*/
【以下不推薦使用代碼字符串!】
/**
* setTimeout和setInterval的第一個(gè)參數(shù)可以是字符串,
* 同樣如eval,字符串可以解釋為一段動態(tài)生成的函數(shù)代碼!
*
* new Function(..)函數(shù)的行為也類似,最后一個(gè)參數(shù)可以
* 接受代碼字符串,并轉(zhuǎn)化為動態(tài)生成的函數(shù)(前面的參數(shù)是這
* 個(gè)新生成的函數(shù)的形參),此構(gòu)建函數(shù)的語法比eval略微安全
* 一點(diǎn)。
*/
【嚴(yán)格模式下直接禁止!】
// with使用
var obj = {
a: 1,
b: 2
};
// 如果要修改obj中a、b的值,再新增一個(gè)變量c,方式一般如下:
obj.a = 3;
obj.b = 4;
obj.c = 5;
console.log(obj); // {a:3, b:4, c:5}
// 非嚴(yán)格模式下,with可以省略少敲擊鍵盤的事
function foo(param) {
with(param) {
a = 3;
b = 4;
c = 5;
};
}
foo(obj);
console.log(obj); // {a:3, b:4}
console.log(c); // 5.... oh, no!
/**
* 變量c被加入到了全局對象中,類似我們前面講到的『LHS未聲明而直接賦值』
*
* JavaScript 中的 with(..) 可以將一個(gè)沒有或有多個(gè)屬性的對象處理為
* 一個(gè)完全隔離的詞法作用域『創(chuàng)建一個(gè)全新的詞法作用域』,因此這個(gè)對象的
* 屬性也會被處理為定義在這個(gè)作用域中的詞法標(biāo)識符。
*
* 盡管with塊可以將一個(gè)對象處理為詞法作用域,但是這個(gè)塊內(nèi)部正常的var聲明
* 并不會被限制在這個(gè)塊的作用域中,而是被添加到 with 所處的函數(shù)作用域中。
*/
總結(jié)(非嚴(yán)格模式下):
- eval函數(shù)如果接受了含有一個(gè)或多個(gè)聲明的代碼,就會修改其所處的詞法作用域
- with聲明實(shí)際上是根據(jù)你傳遞給它的對象憑空創(chuàng)建了一個(gè)全新的詞法作用域
除了上面所說會改變作用域,最最最重要的原因:
因?yàn)镴S引擎采用謹(jǐn)慎保守原則,當(dāng)遇到上面這些能夠動態(tài)改變作用域的方法時(shí),JS編譯器不會去優(yōu)化這塊代碼,因而導(dǎo)致性能嚴(yán)重下降。