JS系列(三):非嚴(yán)格模式與嚴(yán)格模式

這個(gè)話題涉及面很大,通過學(xué)習(xí),不斷補(bǔ)充。

  • 非嚴(yán)格模式,瀏覽器在此模式下表現(xiàn)會有一些不同,主要體現(xiàn)在:
    1. 變量不需要聲明就能直接賦值;
    2. 作用域也會有些許不同;
    3. 可以使用某些函數(shù),如:eval,with,setTimeout,setInterval,new Function(..);
  • 嚴(yán)格模式,瀏覽器會遵照我們一般開發(fā)習(xí)俗(使用前需聲明:"use strict"):
    1. 變量使用前必需聲明;
    2. 嚴(yán)格限制在作用域中;
    3. 不允許使用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)重下降。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容