前言
ECMAScript 5最早引入了“嚴(yán)格模式”(strict mode)的概念。通過嚴(yán)格模式,可以在函數(shù)內(nèi)部存在的錯(cuò)誤,及時(shí)捕獲一些可能導(dǎo)致編程錯(cuò)誤的ECMAScript 行為。
理解嚴(yán)格模式的規(guī)則非常重要,ECMAScript的下一個(gè)版本將以嚴(yán)格模式為基礎(chǔ)制定。支持嚴(yán)格模式的瀏覽器包括IE10+、Firefox 4+、Safari 5.1+和Chrome。
嚴(yán)格模式的目的
- 消除 JavaScript 語法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為
- 消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全
- 提高編譯器效率,增加運(yùn)行速度
- 為未來新版本的 JavaScript 做好鋪墊
嚴(yán)格模式的開啟
想要開啟嚴(yán)格模式,直接在作用域開始的位置寫上字符串 "use strict";
在全局模式下開啟:
"use strict";
在局部模式下開啟(在函數(shù)中打開嚴(yán)格模式):
function fn(){
"use strict";
// 其他代碼
}
嚴(yán)格模式的規(guī)則(執(zhí)行限制)
1、變量 var:消除了偽全局變量
在嚴(yán)格模式下,什么時(shí)候創(chuàng)建變量以及怎么創(chuàng)建變量都是有限制的。不允許意外創(chuàng)建全局變量(就是嚴(yán)格模式下消除了偽全局變量)
// 注意:(function(){})()是一個(gè)匿名函數(shù)
(function () {
a = 10;
console.log(a);
})(); // 結(jié)果:10
(function () {
"use strict";
a = 10;
})(); // 報(bào)錯(cuò):ReferenceError: a is not defined
在非嚴(yán)格模式下,即使變量 a 前面沒有 var 關(guān)鍵字,即使沒有將它定義為某個(gè)全局對象的屬性,也能將 a 創(chuàng)建為偽全局變量使用。
在嚴(yán)格模式下,如果給一個(gè)沒有聲明的變量賦值,那代碼在執(zhí)行的適合就會拋出 ReferenceError(引用錯(cuò)誤)
2、對函數(shù)參數(shù)的要求:更為嚴(yán)格
嚴(yán)格模式要求命名函數(shù)的參數(shù)必須唯一
(function () {
function foo(a ,a, b){
console.log(a,b);
}
foo(1,2,3)
})(); // 結(jié)果: 2 3
(function () {
"use strict";
function foo(a ,a, b){
console.log(a,b);
}
foo(1,2,3)
})(); // 報(bào)錯(cuò):SyntaxError: Duplicate parameter name not allowed in this context
在非嚴(yán)格模式下,這個(gè)函數(shù)聲明不會拋出錯(cuò)誤。通過參數(shù)名只能訪問重復(fù)參數(shù)的第二個(gè)參數(shù),要訪問第一個(gè)重復(fù)參數(shù),必須通過arguments對象(請見下一條)。
在嚴(yán)格模式下,上面函數(shù)參數(shù)的不規(guī)范會拋出 SyntaxError(對象代表嘗試解析語法上不合法的代碼的錯(cuò)誤)
3、實(shí)參形參 和 arguments 的分離
在嚴(yán)格模式下,arguments 對象的行為有所不同。在非嚴(yán)格模式下,修改命名參數(shù)的值也會反映到 arguments 對象中,而嚴(yán)格模式下這兩個(gè)值是完全獨(dú)立的。
// arguments 會受到 形參賦值的影響;
(function(){
function foo(a,b){
a = 20;
console.log(a,b); // 20 2
console.log(arguments[0],arguments[1]); // 20 2
}
foo(1,2)
})();
(function(){
"use strict";
// 形參 和 arguments 之間的區(qū)別;
// 形參是變量可以隨意賦值;
// arguments 就是對應(yīng)實(shí)參的關(guān)鍵字獲取所有的實(shí)參,進(jìn)行使用,不會被改變;
function foo(a,b){
a = 20;
console.log(a,b); // 20 , 2
console.log(arguments[0],arguments[1]); // 1 , 2
}
foo(1,2)
})();
以上代碼中,函數(shù) foo() 傳入兩個(gè)參數(shù) a,b 。調(diào)用這個(gè)函數(shù)時(shí)傳入了兩個(gè)參數(shù)“1,2”,這個(gè)值賦個(gè)了對應(yīng)的變量。而在函數(shù)內(nèi)部,a 的值被修改為“20”。
在非嚴(yán)格模式下,這個(gè)修改的值也會改變 arguments[0] 的值。
但在嚴(yán)格模式下,arguments[0] 的值仍然是傳入的值。
4、arguments 的嚴(yán)格使用,部分功能禁用了
淘汰了 arguments.callee 和 arguments.caller。在非嚴(yán)格模式下,這兩個(gè)屬性一個(gè)是引用函數(shù)本身,一個(gè)是引用調(diào)用函數(shù)。而在嚴(yán)格模式下,這兩個(gè)屬性都被禁用了。
(function(){
function foo(){
// arguments.callee 指向了當(dāng)前的函數(shù)本身;
console.log(arguments.callee);
}
foo()
})(); // 結(jié)果 ? foo(){console.log(arguments.callee);}
(function(){
"use strict";
function foo(){
// 禁用掉了大部分arguments的屬性;
console.log(arguments.callee)
}
foo()
})(); // 報(bào)錯(cuò):TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments
類似的,嘗試讀寫函數(shù)的 caller 屬性也會拋出 TypeError(類型錯(cuò)誤)。
5、嚴(yán)格模式之中對 this 的嚴(yán)格(抑制this)
JavaScript 中一個(gè)最大的安全問題,也是最容易讓人迷惑的地方就是在某些情況下如何抑制 this 的值。在非嚴(yán)格模式下,null 或 undefined 值會被轉(zhuǎn)換為全局對象window。而在嚴(yán)格模式下,函數(shù)的 this 值始終是指定的值,無論指定的是什么值。
(function(){
function foo(){
// this 指向 window;
console.log(this);
}
foo()
})(); // 結(jié)果:Window
(function(){
"use strict";
function foo(){
// 禁用指向了 window 的 this,讓 this 指向 undefined
console.log(this);
}
foo()
})(); // 結(jié)果:undefined
在以后的編程之中,this 最沒有用的指向就是 全局對象window。
6、禁用 with(){} 語句
在非嚴(yán)格模式下的 with 語句能夠改變解析標(biāo)識符的路徑,但在嚴(yán)格模式下,with 被拋棄了。因此,在嚴(yán)格模式下使用 with 會導(dǎo)致語法錯(cuò)誤。
(function(){
with(Math){
// 可以省略對象前置;
console.log(random()); // => Math.random()
console.log(PI); // => Math.PI
}
})();
// 嚴(yán)格模式之下禁用 with(){}
(function(){
"use strict";
with(Math){
console.log(random());
console.log(PI);
}
})(); // 報(bào)錯(cuò):Uncaught SyntaxError: Strict mode code may not include a with statement
在非嚴(yán)格模式下,with可以改變作用域鏈,他可以讓他里面的代碼的作用域鏈的最頂端變成with括號里面的這個(gè)對象,作用域鏈?zhǔn)墙?jīng)過很復(fù)雜的情況生成的結(jié)構(gòu),作用域鏈改了之后,系統(tǒng)內(nèi)核會消耗大量的效率去更改作用域鏈,是會把程序變得非常慢的。所以ES5 的嚴(yán)格模式為了提高效率,禁用 with 語句
7、在嚴(yán)格模式之中被禁用的進(jìn)制:不允許使用八進(jìn)制
以 0 開頭的八進(jìn)制字面量過去經(jīng)常會導(dǎo)致很多錯(cuò)誤,在嚴(yán)格模式下,八進(jìn)制字面量已經(jīng)成為無效的語法了。
(function(){
// 0 開頭就是八進(jìn)制的標(biāo)志;
console.log(012);
})(); // 結(jié)果: 10 (自動轉(zhuǎn)化成十進(jìn)制)
(function(){
"use strict"
console.log(012)
})(); //報(bào)錯(cuò):Uncaught SyntaxError: Octal literals are not allowed in strict mode.
補(bǔ)充:ES5 也修改了嚴(yán)格模式下的 parseInt() 的行為。如今八進(jìn)制的字面量在嚴(yán)格模式下會被當(dāng)作以 0 開頭的十進(jìn)制字面量。例如:
(function(){
var value = 012;
console.log(value);
})(); // 結(jié)果: 10
(function(){
"use strict";
var value = parseInt("012");
console.log(value);
})(); // 結(jié)果: 12
如有遺漏之處歡迎評論區(qū)留言。