通過嚴(yán)格模式,可以在函數(shù)內(nèi)部 選擇進行較為嚴(yán)格的全局或局部的錯誤條件檢測。使用嚴(yán)格模式的好處是可以提早知道代碼中存在的錯誤,及時捕獲一些可能導(dǎo)致編程錯誤的ECMAScript行為。
支持嚴(yán)格模式的瀏覽器包括IE10+、Firefox 4+、Safari 5.1+和Chrome。
選擇使用
要選擇進入嚴(yán)格模式,可以使用嚴(yán)格模式的編譯指示:
"use strict";
這種語法可以向后兼容那些不支持嚴(yán)格模式的JavaScript引擎。支持嚴(yán)格模式的引擎會啟動這種模式,而不支持該模式的引擎就當(dāng)遇到了一個未賦值的字符串字面量,會忽略這個編譯指示。
如果是在全局作用域中(函數(shù)外部)給出這個編譯指示,則整個腳本都將使用嚴(yán)格模式。也可以只在函數(shù)中打開嚴(yán)格模式:
function doSomething(){
"use strict";
//其他代碼
}
變量
在嚴(yán)格模式下,什么時候創(chuàng)建變量以及怎么創(chuàng)建變量都是有限制的。首先,不允許意外創(chuàng)建全局變量。
//未聲明變量
//非嚴(yán)格模式:創(chuàng)建全局變量
//嚴(yán)格模式:拋出 ReferenceError
message = "Hello world! ";
其次,不能對變量調(diào)用delete操作符。非嚴(yán)格模式允許這樣操作,但會靜默失?。ǚ祷?code>false)。 而在嚴(yán)格模式下,刪除變量也會導(dǎo)致錯誤。
//刪除變量
//非嚴(yán)格模式:靜默失敗
//嚴(yán)格模式:拋出 ReferenceError
var color = "red";
delete color;
嚴(yán)格模式下對變量名也有限制。特別地,不能使用implements、interface、let、package、private、protected、public、static和yield作為變量名。這些都是保留字。在嚴(yán)格模式下,用以上標(biāo)識符作為變量名會導(dǎo)致語法錯誤。
對象
一般來說,非嚴(yán)格模式下會靜默失敗的情形,在嚴(yán)格模式下就會拋出錯誤。
在下列情形下操作對象的屬性會導(dǎo)致錯誤:
- 為只讀屬性賦值會拋出
TypeError; - 對不可配置的的屬性使用
delete操作符會拋出TypeError; - 為不可擴展的的對象添加屬性會拋出
TypeError。
使用對象的另一個限制與通過對象字面量聲明對象有關(guān)。在使用對象字面量時,屬性名必須唯一。例如:
//重名屬性
//非嚴(yán)格模式:沒有錯誤,以第二個屬性為準(zhǔn)
//嚴(yán)格模式:拋出語法錯誤
var person = {
name: "Nicholas",
name: "Greg"
};
函數(shù)
首先,嚴(yán)格模式要求命名函數(shù)的參數(shù)必須唯一。
//重名參數(shù)
//非嚴(yán)格模式:沒有錯誤,只能訪問第二個參數(shù)
//嚴(yán)格模式:拋出語法錯誤
function sum (num, num){
//do something
}
在非嚴(yán)格模式下,這個函數(shù)聲明不會拋出錯誤。通過參數(shù)名只能訪問第二個參數(shù),要訪問第一個參數(shù)必須通過arguments對象。
在嚴(yán)格模式下,arguments對象的行為也有所不同。在非嚴(yán)格模式下,修改命名參數(shù)的值也會反映到arguments對象中,而嚴(yán)格模式下這兩個值是完全獨立的。
//修改命名參數(shù)的值
//非嚴(yán)格模式:修改會反映到 arguments 中
//嚴(yán)格模式:修改不會反映到 arguments 中
function showValue(value){
value = "Foo";
alert(value); //"Foo"
alert(arguments[0]); //非嚴(yán)格模式:"Foo"
//嚴(yán)格模式:"Hi"
}
showValue("Hi");
在函數(shù)內(nèi)部,value被改為"Foo"。在非嚴(yán)格模式下,這個修改也會改變arguments[0]的值,但在嚴(yán)格模式下,arguments[0]的值仍然是傳入的值。
另一個變化是淘汰了arguments.callee和arguments.caller。在非嚴(yán)格模式下,這兩個屬性一個引用函數(shù)本身,一個引用調(diào)用函數(shù)。而在嚴(yán)格模式下,訪問哪個屬性都會拋出TypeError。
//訪問 arguments.callee
//非嚴(yán)格模式:沒有問題
//嚴(yán)格模式:拋出 TypeError
function factorial(num){
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num-1)
}
}
var result=factorial(5);
類似地,嘗試讀寫函數(shù)的caller屬性,也會導(dǎo)致拋出TypeError。所以,對于上面的例子而言, 訪問factorial.caller也會拋出錯誤。
與變量類似,嚴(yán)格模式對函數(shù)名也做出了限制,不允許用implements、interface、let、package、 private、protected、public、static和yield作為函數(shù)名。
對函數(shù)的最后一點限制,就是只能在腳本的頂級和在函數(shù)內(nèi)部聲明函數(shù)。也就是說,在if語句中聲明函數(shù)會導(dǎo)致語法錯誤:
//在 if 語句中聲明函數(shù)
//非嚴(yán)格模式:將函數(shù)提升到 if 語句外部
//嚴(yán)格模式:拋出語法錯誤
if (true){
function doSomething(){
//...
}
}
eval()
eval()函數(shù)在嚴(yán)格模式下也得到了提升。最大的變化就是它在包含上下文中不再創(chuàng)建變量或函數(shù)。
//使用 eval()創(chuàng)建變量
//非嚴(yán)格模式:彈出對話框顯示 10
//嚴(yán)格模式:調(diào)用 alert(x)時會拋出 ReferenceError
function doSomething(){
eval("var x=10");
alert(x);
}
如果是在非嚴(yán)格模式下,以上代碼會在函數(shù)doSomething()中創(chuàng)建一個局部變量x,然后alert()還會顯示該變量的值。但在嚴(yán)格模式下,在doSomething()函數(shù)中調(diào)用eval()不會創(chuàng)建變量x,因此調(diào)用alert()會導(dǎo)致拋出ReferenceError,因為x沒有定義。
可以在eval()中聲明變量和函數(shù),但這些變量或函數(shù)只能在被求值的特殊作用域中有效,隨后就將被銷毀。
"use strict";
var result = eval("var x=10, y=11; x+y");
alert(result); //21
在調(diào)用alert()時,盡管x和y已經(jīng)不存在了,result變量的值仍然是有效的。
eval與arguments
嚴(yán)格模式已經(jīng)明確禁止使用eval和arguments作為標(biāo)識符,也不允許讀寫它們的值。
//把eval和arguments作為變量引用
//非嚴(yán)格模式:沒問題,不出錯
//嚴(yán)格模式:拋出語法錯誤
var eval = 10;
var arguments = "Hello world!";
在非嚴(yán)格模式下,可以重寫eval,也可以給arguments賦值。但在嚴(yán)格模式下,這樣做會導(dǎo)致語法錯誤。不能將它們用作標(biāo)識符,意味著以下幾種使用方式都會拋出語法錯誤:
- 使用
var聲明; - 賦予另一個值;
- 嘗試修改包含的值,如使用++;
- 用作函數(shù)名;
- 用作命名的函數(shù)參數(shù);
- 在
try-catch語句中用作例外名。
抑制this
在非嚴(yán)格模式下使用函數(shù)的apply()或call()方法時,null或undefined值會被轉(zhuǎn)換為全局對象。而在嚴(yán)格模式下,函數(shù)的this值始終是指定的值,無論指定的是什么值。
//訪問屬性
//非嚴(yán)格模式:訪問全局屬性
//嚴(yán)格模式:拋出錯誤,因為this的值為null
var color = "red";
function displayColor(){
alert(this.color);
}
displayColor.call(null);
其他變化
首先是拋棄了with語句。非嚴(yán)格模式下的with語句能夠改變解析標(biāo)識符的路徑,但在嚴(yán)格模式下,with被簡化掉了。因此,在嚴(yán)格模式下使用with會導(dǎo)致語法錯誤。
//with的語句用法
//非嚴(yán)格模式:允許
//嚴(yán)格模式:拋出語法錯誤
with(location){
alert(href);
}
嚴(yán)格模式也去掉了JavaScript中的八進制字面量。以0開頭的八進制字面量過去經(jīng)常會導(dǎo)致很多錯誤。在嚴(yán)格模式下,八進制字面量已經(jīng)成為無效的語法了。
//使用八進制字面量
//非嚴(yán)格模式:值為 8
//嚴(yán)格模式:拋出語法錯誤
var value = 010;
八進制字面量在嚴(yán)格模式下會被當(dāng)作以0開頭的十進制字面量。
//使用parseInt()解析八進制字面量
//非嚴(yán)格模式:值為 8
//嚴(yán)格模式:值為 10
var value = parseInt("010");