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