前言
ECMAScript 5最早引入了“嚴(yán)格模式”(strict mode)的概念。通過嚴(yán)格模式纫雁,可以在函數(shù)內(nèi)部存在的錯誤,及時捕獲一些可能導(dǎo)致編程錯誤的ECMAScript 行為榕吼。
理解嚴(yán)格模式的規(guī)則非常重要继低,ECMAScript的下一個版本將以嚴(yán)格模式為基礎(chǔ)制定竹宋。支持嚴(yán)格模式的瀏覽器包括IE10+劳澄、Firefox 4+、Safari 5.1+和Chrome蜈七。
嚴(yán)格模式的目的
- 消除 JavaScript 語法的一些不合理秒拔、不嚴(yán)謹(jǐ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)格模式下庵芭,什么時候創(chuàng)建變量以及怎么創(chuàng)建變量都是有限制的。不允許意外創(chuàng)建全局變量(就是嚴(yán)格模式下消除了偽全局變量)
// 注意:(function(){})()是一個匿名函數(shù)
(function () {
a = 10;
console.log(a);
})(); // 結(jié)果:10
(function () {
"use strict";
a = 10;
})(); // 報錯:ReferenceError: a is not defined
在非嚴(yán)格模式下雀监,即使變量 a 前面沒有 var 關(guān)鍵字双吆,即使沒有將它定義為某個全局對象的屬性,也能將 a 創(chuàng)建為偽全局變量使用会前。
在嚴(yán)格模式下好乐,如果給一個沒有聲明的變量賦值,那代碼在執(zhí)行的適合就會拋出 ReferenceError(引用錯誤)
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)
})(); // 報錯:SyntaxError: Duplicate parameter name not allowed in this context
在非嚴(yán)格模式下蔚万,這個函數(shù)聲明不會拋出錯誤。通過參數(shù)名只能訪問重復(fù)參數(shù)的第二個參數(shù)临庇,要訪問第一個重復(fù)參數(shù)反璃,必須通過arguments對象(請見下一條)。
在嚴(yán)格模式下假夺,上面函數(shù)參數(shù)的不規(guī)范會拋出 SyntaxError(對象代表嘗試解析語法上不合法的代碼的錯誤)
3版扩、實參形參 和 arguments 的分離
在嚴(yán)格模式下,arguments 對象的行為有所不同侄泽。在非嚴(yán)格模式下礁芦,修改命名參數(shù)的值也會反映到 arguments 對象中,而嚴(yán)格模式下這兩個值是完全獨立的悼尾。
// 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)實參的關(guān)鍵字獲取所有的實參柿扣,進(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() 傳入兩個參數(shù) a析桥,b 司草。調(diào)用這個函數(shù)時傳入了兩個參數(shù)“1艰垂,2”,這個值賦個了對應(yīng)的變量埋虹。而在函數(shù)內(nèi)部猜憎,a 的值被修改為“20”。
在非嚴(yán)格模式下搔课,這個修改的值也會改變 arguments[0] 的值胰柑。
但在嚴(yán)格模式下,arguments[0] 的值仍然是傳入的值爬泥。
4柬讨、arguments 的嚴(yán)格使用,部分功能禁用了
淘汰了 arguments.callee 和 arguments.caller袍啡。在非嚴(yán)格模式下踩官,這兩個屬性一個是引用函數(shù)本身,一個是引用調(diào)用函數(shù)境输。而在嚴(yán)格模式下卖鲤,這兩個屬性都被禁用了。
(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()
})(); // 報錯:TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments
類似的畴嘶,嘗試讀寫函數(shù)的 caller 屬性也會拋出 TypeError(類型錯誤)。
5集晚、嚴(yán)格模式之中對 this 的嚴(yán)格(抑制this)
JavaScript 中一個最大的安全問題窗悯,也是最容易讓人迷惑的地方就是在某些情況下如何抑制 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)致語法錯誤鲫尊。
(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);
}
})(); // 報錯:Uncaught SyntaxError: Strict mode code may not include a with statement
在非嚴(yán)格模式下,with可以改變作用域鏈沦偎,他可以讓他里面的代碼的作用域鏈的最頂端變成with括號里面的這個對象疫向,作用域鏈?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)致很多錯誤堆巧,在嚴(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)
})(); //報錯:Uncaught SyntaxError: Octal literals are not allowed in strict mode.
補充: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ū)留言哗伯。