Javascript 嚴格模式詳解

jopen 11年前發布 | 24K 次閱讀 JavaScript開發 JavaScript

        一、概述

        除了正常運行模式,ECMAscript 5 添加了第二種運行模式:"嚴格模式"(strict mode)。顧名思義,這種模式使得 Javascript 在更嚴格的條件下運行。

Javascript 嚴格模式詳解

 

        設立"嚴格模式"的目的,主要有以下幾個:

- 消除 Javascript 語法的一些不合理、不嚴謹之處,減少一些怪異行為;

- 消除代碼運行的一些不安全之處,保證代碼運行的安全;

- 提高編譯器效率,增加運行速度;

- 為未來新版本的 Javascript 做好鋪墊。

        "嚴格模式"體現了 Javascript 更合理、更安全、更嚴謹的發展方向,包括 IE 10 在內的主流瀏覽器,都已經支持它,許多大項目已經開始全面擁抱它。

        另一方面,同樣的代碼,在"嚴格模式"中,可能會有不一樣的運行結果;一些在"正常模式"下可以運行的語句,在"嚴格模式"下將不能運行。掌握這些內容,有助于更細致深入地理解 Javascript,讓你變成一個更好的程序員。

        本文將對"嚴格模式"做詳細介紹。

        二、進入標志

        進入"嚴格模式"的標志,是下面這行語句:

"use strict";

        老版本的瀏覽器會把它當作一行普通字符串,加以忽略。

        三、如何調用

        "嚴格模式"有兩種調用方法,適用于不同的場合。

        3. 1 針對整個腳本文件

        將"use strict"放在腳本文件的第一行,則整個腳本都將以"嚴格模式"運行。如果這行語句不在第一行,則無效,整個腳本以"正常模式"運行。如果不同模式的代碼文件合并成一個文件,這一點需要特別注意。

        上面的代碼表示,一個網頁中依次有兩段 Javascript 代碼。前一個 script 標簽是嚴格模式,后一個不是。

        3. 2 針對單個函數

        將"use strict"放在函數體的第一行,則整個函數以"嚴格模式"運行。

function strict (){

"use strict";

return "這是嚴格模式。";

}

function notStrict () {

return "這是正常模式。";

}

        3. 3 腳本文件的變通寫法

        因為第一種調用方法不利于文件合并,所以更好的做法是,借用第二種方法,將整個腳本文件放在一個立即執行的匿名函數之中。

(function (){

"use strict";

// some code here

})();

        四、語法和行為改變

        嚴格模式對 Javascript 的語法和行為,都做了一些改變。

        4. 1 全局變量顯式聲明

        在正常模式中,如果一個變量沒有聲明就賦值,默認是全局變量。嚴格模式禁止這種用法,全局變量必須顯式聲明。

"use strict";

v = 1; // 報錯,v未聲明

for (i = 0; i < 2; i++) { // 報錯,i未聲明

}

        因此,嚴格模式下,變量都必須先用 var 命令聲明,然后再使用。

        4. 2 靜態綁定

        Javascript 語言的一個特點,就是允許"動態綁定",即某些屬性和方法到底屬于哪一個對象,不是在編譯時確定的,而是在運行時(runtime)確定的。

        嚴格模式不允許動態綁定,只允許靜態綁定。也就是說,屬性和方法到底歸屬哪個對象,必須在編譯階段就確定。這樣做有利于編譯效率的提高,也使得代碼更容易閱讀,更少出現意外。

        具體來說,涉及以下幾個方面。

        (1)禁止使用 with 語句

        因為 with 語句無法在編譯時就確定,屬性到底歸屬哪個對象。

"use strict";

var v = 1;

with (o){ // 語法錯誤

v = 2;

}

        (2)創設 eval 作用域

        正常模式下,Javascript 語言有兩種變量作用域(scope):全局作用域和函數作用域。嚴格模式創設了第三種作用域:eval 作用域。

        正常模式下,eval 語句的作用域,取決于它處于全局作用域,還是函數作用域。嚴格模式下,eval 語句本身就是一個作用域,不再能夠生成全局變量了,它所生成的變量只能用于 eval 內部。

"use strict";

var x = 2;

console.info (eval ("var x = 5; x")); // 5

console.info (x); // 2

        4. 3 增強的安全措施

        (1)禁止 this 關鍵字指向全局對象

function f (){

return !this;

}

// 返回 false,因為"this"指向全局對象,"!this"就是 false

function f (){

"use strict";

return !this;

}

// 返回 true,因為嚴格模式下,this 的值為 undefined,所以"!this"為 true。

        因此,使用構造函數時,如果忘了加 new,this 不再指向全局對象,而是報錯。

function f (){

"use strict";

this.a = 1;

};

f();// 報錯,this 未定義

        (2)禁止在函數內部遍歷調用棧

function f1(){

"use strict";

f1.caller; // 報錯

f1.arguments; // 報錯

}

f1();

        4. 4 禁止刪除變量

        嚴格模式下無法刪除變量。只有 configurable 設置為 true 的對象屬性,才能被刪除。

"use strict";

var x;

delete x; // 語法錯誤

var o = Object.create (null, 'x', {

value: 1,

configurable: true

});

delete o.x; // 刪除成功

        4. 5 顯式報錯

        正常模式下,對一個對象的只讀屬性進行賦值,不會報錯,只會默默地失敗。嚴格模式下,將報錯。

"use strict";

var o = {};

Object.defineProperty (o, "v", { value: 1, writable: false });

o.v = 2; // 報錯

        嚴格模式下,對一個使用 getter 方法讀取的屬性進行賦值,會報錯。

"use strict";

var o = {

get v () { return 1; }

};

o.v = 2; // 報錯

        嚴格模式下,對禁止擴展的對象添加新屬性,會報錯。

"use strict";

var o = {};

Object.preventExtensions (o);

o.v = 1; // 報錯

        嚴格模式下,刪除一個不可刪除的屬性,會報錯。

"use strict";

delete Object.prototype; // 報錯

        4. 6 重名錯誤

        嚴格模式新增了一些語法錯誤。

        (1)對象不能有重名的屬性

        正常模式下,如果對象有多個重名屬性,最后賦值的那個屬性會覆蓋前面的值。嚴格模式下,這屬于語法錯誤。

"use strict";

var o = {

p: 1,

p: 2

}; // 語法錯誤

        (2)函數不能有重名的參數

        正常模式下,如果函數有多個重名的參數,可以用 arguments[i]讀取。嚴格模式下,這屬于語法錯誤。

"use strict";

function f (a, a, b) { // 語法錯誤

return ;

}

        4. 7 禁止八進制表示法

        正常模式下,整數的第一位如果是0,表示這是八進制數,比如 0100 等于十進制的 64。嚴格模式禁止這種表示法,整數第一位為0,將報錯。

"use strict";

var n = 0100; // 語法錯誤

        4. 8 arguments 對象的限制

        arguments 是函數的參數對象,嚴格模式對它的使用做了限制。

        (1)不允許對 arguments 賦值

"use strict";

arguments++; // 語法錯誤

var obj = { set p (arguments) { } }; // 語法錯誤

try { } catch (arguments) { } // 語法錯誤

function arguments () { } // 語法錯誤

var f = new Function ("arguments", "'use strict'; return 17;"); // 語法錯誤

        (2)arguments 不再追蹤參數的變化

function f (a) {

a = 2;

return [a, arguments[0]];

}

f(1); // 正常模式為[2,2]

function f (a) {

"use strict";

a = 2;

return [a, arguments[0]];

}

f(1); // 嚴格模式為[2,1]

        (3)禁止使用 arguments.callee

        這意味著,你無法在匿名函數內部調用自身了。

"use strict";

var f = function () { return arguments.callee; };

f(); // 報錯

        4. 9 函數必須聲明在頂層

        將來 Javascript 的新版本會引入"塊級作用域"。為了與新版本接軌,嚴格模式只允許在全局作用域或函數作用域的頂層聲明函數。也就是說,不允許在非函數的代碼塊內聲明函數。

"use strict";

if (true) {

function f () { } // 語法錯誤

}

for (var i = 0; i < 5; i++) {

function f2() { } // 語法錯誤

}

        4. 10 保留字

        為了向將來 Javascript 的新版本過渡,嚴格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

        使用這些詞作為變量名將會報錯。

function package (protected) { // 語法錯誤

"use strict";

var implements; // 語法錯誤

}

        此外,ECMAscript 第五版本身還規定了另一些保留字:class, enum, export, extends, import, super。它們也是不能使用的。

        五、參考鏈接

        - MDN, Strict mode

        - Dr. Axel Rauschmayer,JavaScript's strict mode: a summary

        - Douglas Crockford, Strict Mode Is Coming To Town

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!