Javascript的嚴格模式
在嚴格模式下,能夠在函式內部選擇進行較為嚴格的全域性或區域性的錯誤條件檢測。使用嚴格模式的好處是可以提早知道程式碼中存在的錯誤,即使捕獲一些可能導致程式設計uowu的ECMAScript行為。
理解嚴格模式的規範非常重要,ECMAScript的下一個版本將以嚴格模式為基礎指定。支援嚴格模式的瀏覽器包括IE10+,Firefox4+, Safari5.1+和Chrome。
選擇使用
要選擇進入嚴格模式,可以使用嚴格模式的編譯指示,實際上就是一個不會賦給任何變數的字串:use strict;
在老版本的瀏覽器裡,會把它當做一行普通的字串,加以葫蘆。
如果在全域性作用域中(函式外部)給出這個編譯知識,則整個指令碼都將使用嚴格模式。換句話說,如果把帶有這個編譯指示的指令碼放到其他檔案中,則該檔案中的Javascript程式碼將處於嚴格模式下。
也可以只在函式中開啟嚴格模式,就像下面這樣:
function doSomething(){"use strict";// 其他程式碼}
如果你沒有控制頁面中所有指令碼的權利,建議只在需要測試的特定函式中開啟嚴格模式。
變數
在嚴格模式下,什麼時候建立變數以及怎麼建立變數都是有限制的。首先,不允許意外建立全域性變數。在非嚴格模式下,可以像下面這樣建立全域性變數。// 未宣告變數// 非嚴格模式:建立全域性變數// 嚴格模式:丟擲錯誤
message ="hello wenzi";
即使message前面沒有var關鍵字,即使沒有將它定義為某個全域性物件的屬性,也能將message為全域性變數。但在嚴格模式下,如果給一個沒有宣告的變數賦值,那程式碼在執行時就會丟擲錯誤。
其實不能對變數呼叫delete操作符。非嚴格模式允許這樣操作,單戶靜默失敗(返回false),而在嚴格模式下,刪除變數也會導致錯誤。
// 刪除變數// 非嚴格模式:靜默失敗// 嚴格模式:丟擲錯誤var color ="red";delete color;
嚴格模式下對變數名也有限制。特別地,不能使用implements
, interface
, protected
, public
, static
和yield
作為變數名。這些都是保留字,將來的ES版本中可能會使用到他們。在嚴格模式,用以上的識別符號作為變數會導致語法錯誤。
物件
在嚴格模式下操作物件比在非嚴格模式下更容易導致錯誤。一般來說,非嚴格模式下會靜默失敗的情形,在嚴格模式下就會丟擲錯誤。因此在開發中使用嚴格模式更能發現錯誤。
在下列情形下操作物件的屬性會導致錯誤: + 為只讀屬性進行賦值; + 為不可配置的屬性使用delete操作符; + 為不可擴充套件的物件新增誰能夠 使用物件的另一個限制與通過物件字面量宣告物件有關。在使用物件字面量時,屬性名必須唯一
// 重名屬性// 非嚴格模式:沒有錯誤,以第二個屬性為準// 嚴格模式:丟擲語法錯誤var student ={
name :'wenzi',
name :'bing'}
這裡的物件student有兩個屬性,都叫name。在非嚴格模式下,student物件的name屬性值是第二個,而在嚴格模式下,這樣的程式碼會導致語法錯誤。
函式
首先,嚴格模式下要求明明函式的引數必須唯一。以下面這個函式為例:
// 重名引數// 非嚴格模式:沒有錯誤,只能訪問第二個引數// 嚴格模式:丟擲語法錯誤function doSomething(num, num){// 其他程式碼}
在非嚴格模式下,這個函式宣告不會丟擲錯誤。通過引數名只能訪問第二個引數,要訪問第一個引數必須通過arguments物件。
在嚴格模式下,arguments物件的行為也有所不同,在非嚴格模式下,修改明明引數的值也會反應到arguments物件中,而嚴格模式下這兩個值是完全獨立的。如:
// 修改命名引數的值// 非嚴格模式:修改會反應到arguments中// 嚴格模式:修改不會反應到arguments中function doSomething(value){
value =7;
console.log(value, arguments[0]);// 非嚴格模式下,輸出:7, 7// 嚴格模式下,輸出:7, 10}
doSomething(10);
另一個變化是淘汰了arguments.callee和arguments.caller。在非嚴格模式下,這兩個屬性一個引用函式本身,一個引用呼叫函式。而在嚴格模式下,訪問哪個屬性都會丟擲TypeError。例如:
// 訪問arguments.callee// 非嚴格模式:正常// 嚴格模式:丟擲錯誤function factorial(num){if(num<=)return1;return num*arguments.callee(num-1);}var result = factorial(4);
與變數類似,嚴格模式對函式名也作出了限制,不允許使用implements
, interface
, protected
, public
,static
和yield
作為函式名。
對函式的最後一點限制,就是隻能在指令碼的頂級和在函式內部宣告函式。而在if語句中宣告函式與導致語法錯誤:
if(true){function doSomething(){// ...}}
在非嚴格模式下,以上程式碼在所有的瀏覽器上都能執行;而嚴格模式下會導致語法錯誤。
###eval()
飽受詬病的eval()在嚴格模式下也得到了提升。最大的變化就是它在包含上下文中不再建立變數或函式。例如:
// 使用eval()建立變數// 非嚴格模式:彈出對話方塊顯示10// 嚴格模式:丟擲錯誤function doSomething(){eval("x=10");
alert(x);}
如果在非嚴格模式下,以上程式碼在函式中會建立一個區域性變數x,然後alert(),還會顯示該變數的值。但在嚴格模式下,在doSomething()函式呼叫eval()不會建立變數x,因此呼叫alert()會導致丟擲錯誤,因為x沒有定義。
可以在eval()中宣告變數和函式,但這些變數或函式只能在被求值的特殊作用域中有效,隨後就將被銷燬。
其他變化
嚴格模式還有其他一些變化,希望能夠注意。首先是拋棄了with語句。非嚴格模式下的with能夠改變解析變支付的路徑,但在嚴格模式下,with被簡化掉了。因此,在嚴格模式使用with會導致語法錯誤。
// with語句// 非嚴格模式:允許// 嚴格模式:丟擲錯誤with(location){
alert(href);}
嚴格模式下也去掉了Javascript中的八進位制字面量。以0開頭的八進位制字面量經常會導致很多錯誤。在嚴格模式下,八進位制字面量已經成為了無效的語法了。
// 使用八進位制字面量// 非嚴格模式:值為8// 嚴格模式:丟擲語法錯誤var value =010;
ES5也修改了嚴格模式下parseInt()的行為。如今,八進位制字面量在嚴格模式下會被當做以0開頭的十進位制字面量。例如:
// 使用parseInt()解析八進位制字面量// 非嚴格模式:值為0// 嚴格模式:值為10var value = parseInt("010");