ECMAScript 5 最先引入了「嚴格模式」(strict mode)的概念。經過嚴格模式,能夠在函數內部編程
選擇進行較爲嚴格的全局或局部的錯誤條件檢測。使用嚴格模式的好處是能夠提前知道代碼中瀏覽器
存在的錯誤,及時捕獲一些可能致使編程錯誤的ECMAScript 行爲。安全
理解嚴格模式的規則很是重要,ECMAScript 的下一個版本將以嚴格模式爲基礎制定。支持嚴格模app
式的瀏覽器包括IE10+、Firefox 4+、Safari 5.1+和Chrome。函數
1.選擇使用測試
要選擇進入嚴格模式,可使用嚴格模式的編譯指示(pragma),實際上就是一個不會賦給任何變this
量的字符串:spa
"use strict";code
這種語法(從ECMAScript 3 開始支持)能夠向後兼容那些不支持嚴格模式的JavaScript 引擎。支持orm
嚴格模式的引擎會啓動這種模式,而不支持該模式的引擎就當遇到了一個未賦值的字符串字面量,會忽
略這個編譯指示。
若是是在全局做用域中(函數外部)給出這個編譯指示,則整個腳本都將使用嚴格模式。換句話說,
若是把帶有這個編譯指示的腳本放到其餘文件中,則該文件中的JavaScript 代碼也將處於嚴格模式下。
也能夠只在函數中打開嚴格模式,就像下面這樣:
function doSomething(){"use strict";//其餘代碼}
若是你沒有控制頁面中全部腳本的權力,建議只在須要測試的特定函數中開啓嚴格模式。
2 .變量
在嚴格模式下,何時建立變量以及怎麼建立變量都是有限制的。首先,不容許意外建立全局變
量。在非嚴格模式下,能夠像下面這樣建立全局變量:
//未聲明變量//非嚴格模式:建立全局變量//嚴格模式:拋出ReferenceErrormessage = "Hello world! ";
即便message 前面沒有var 關鍵字,即便沒有將它定義爲某個全局對象的屬性,也能將message
建立爲全局變量。但在嚴格模式下,若是給一個沒有聲明的變量賦值,那代碼在執行時就會拋出
ReferenceError。
其次,不能對變量調用delete 操做符。非嚴格模式容許這樣操做,但會靜默失敗(返回false)。
而在嚴格模式下,刪除變量也會致使錯誤。
//刪除變量//非嚴格模式:靜默失敗//嚴格模式:拋出ReferenceErrorvar color = "red";delete color;
嚴格模式下對變量名也有限制。特別地,不能使用implements、interface、let、package、
private、protected、public、static 和yield 做爲變量名。這些都是保留字,未來的ECMAScript
版本中可能會用到它們。在嚴格模式下,用以上標識符做爲變量名會致使語法錯誤。
3.對象
在嚴格模式下操做對象比在非嚴格模式下更容易致使錯誤。通常來講,非嚴格模式下會靜默失敗的
情形,在嚴格模式下就會拋出錯誤。所以,在開發中使用嚴格模式會加大早發現錯誤的可能性。
在下列情形下操做對象的屬性會致使錯誤:
爲只讀屬性賦值會拋出TypeError;
對不可配置的(nonconfigurable)的屬性使用delete 操做符會拋出TypeError;
爲不可擴展的(nonextensible)的對象添加屬性會拋出TypeError。
使用對象的另外一個限制與經過對象字面量聲明對象有關。在使用對象字面量時,屬性名必須惟一。
例如:
//重名屬性//非嚴格模式:沒有錯誤,以第二個屬性爲準//嚴格模式:拋出語法錯誤var person = { name: "Nicholas", name: "Greg"};
這裏的對象person 有兩個屬性,都叫name。在非嚴格模式下,person 對象的name 屬性值是第
二個,而在嚴格模式下,這樣的代碼會致使語法錯誤。
4.函數
首先,嚴格模式要求命名函數的參數必須惟一。如下面這個函數爲例:
//重名參數//非嚴格模式:沒有錯誤,只能訪問第二個參數//嚴格模式:拋出語法錯誤function sum (num, num){//do something}
在非嚴格模式下,這個函數聲明不會拋出錯誤。經過參數名只能訪問第二個參數,要訪問第一個參
數必須經過arguments 對象。
在嚴格模式下,arguments 對象的行爲也有所不一樣。在非嚴格模式下,修改命名參數的值也會反
映到arguments 對象中,而嚴格模式下這兩個值是徹底獨立的。例如:
//修改命名參數的值//非嚴格模式:修改會反映到arguments 中//嚴格模式:修改不會反映到arguments 中function showValue(value){ value = "Foo"; alert(value); //"Foo"alert(arguments[0]); //非嚴格模式:"Foo"//嚴格模式:"Hi"} showValue("Hi");
以上代碼中,函數showValue()只有一個命名參數value。調用這個函數時傳入了一個參數"Hi",
這個值賦給了value。而在函數內部,value 被改成"Foo"。在非嚴格模式下,這個修改也會改變
arguments[0]的值,但在嚴格模式下,arguments[0]的值仍然是傳入的值。
另外一個變化是淘汰了arguments.callee 和arguments.caller。在非嚴格模式下,這兩個屬
性一個引用函數自己,一個引用調用函數。而在嚴格模式下,訪問哪一個屬性都會拋出TypeError。
例如:
//訪問arguments.callee//非嚴格模式:沒有問題//嚴格模式:拋出TypeErrorfunction factorial(num){if (num <= 1) {return 1; } else {return num * arguments.callee(num-1) } }var result=factorial(5);
相似地,嘗試讀寫函數的caller 屬性,也會致使拋出TypeError。因此,對於上面的例子而言,
訪問factorial.caller 也會拋出錯誤。
與變量相似,嚴格模式對函數名也作出了限制,不容許用implements、interface、let、package、
private、protected、public、static 和yield 做爲函數名。
對函數的最後一點限制,就是隻能在腳本的頂級和在函數內部聲明函數。也就是說,在if 語句中
聲明函數會致使語法錯誤:
//在if 語句中聲明函數//非嚴格模式:將函數提高到if 語句外部//嚴格模式:拋出語法錯誤if (true){function doSomething(){//...} }
在非嚴格模式下,以上代碼能在全部瀏覽器中運行,但在嚴格模式下會致使語法錯誤。
5.eval()
飽受詬病的eval()函數在嚴格模式下也獲得了提高。最大的變化就是它在包含上下文中再也不建立
變量或函數。例如:
//使用eval()建立變量//非嚴格模式:彈出對話框顯示10//嚴格模式:調用alert(x)時會拋出ReferenceErrorfunction doSomething(){ eval("var x=10"); alert(x); }
若是是在非嚴格模式下,以上代碼會在函數doSomething()中建立一個局部變量x,而後alert()
還會顯示該變量的值。但在嚴格模式下,在doSomething()函數中調用eval()不會建立變量x,所以
調用alert()會致使拋出ReferenceError,由於x 沒有定義。
能夠在eval()中聲明變量和函數,但這些變量或函數只能在被求值的特殊做用域中有效,隨後就
將被銷燬。所以,如下代碼能夠運行,沒有問題:
"use strict";var result = eval("var x=10, y=11; x+y"); alert(result); //21
這裏在eval()中聲明瞭變量x 和y,而後將它們加在一塊兒,返回了它們的和。因而,result 變
量的值是21,即x 和y 相加的結果。而在調用alert()時,儘管x 和y 已經不存在了,result 變量
的值仍然是有效的。
6.eval與arguments
嚴格模式已經明確禁止使用eval 和arguments 做爲標識符,也不容許讀寫它們的值。例如:
//把eval 和arguments 做爲變量引用//非嚴格模式:沒問題,不出錯//嚴格模式:拋出語法錯誤var eval = 10;var arguments = "Hello world!";
在非嚴格模式下,能夠重寫eval,也能夠給arguments 賦值。但在嚴格模式下,這樣作會致使語
法錯誤。不能將它們用做標識符,意味着如下幾種使用方式都會拋出語法錯誤:
使用var 聲明;
賦予另外一個值;
嘗試修改包含的值,如使用++;
用做函數名;
用做命名的函數參數;
在try-catch 語句中用做例外名。
7.抑制this
JavaScript 中一個最大的安全問題,也是最容易讓人迷茫的地方,就是在某些狀況下如何抑制this
的值。在非嚴格模式下使用函數的apply()或call()方法時,null 或undefined 值會被轉換爲全局
對象。而在嚴格模式下,函數的this 值始終是指定的值,不管指定的是什麼值。例如:
//訪問屬性//非嚴格模式:訪問全局屬性//嚴格模式:拋出錯誤,由於this 的值爲nullvar color = "red";function displayColor(){ alert(this.color); } displayColor.call(null);
以上代碼向displayColor.call()中傳入了null,若是在是非嚴格模式下,這意味着函數的this
值是全局對象。結果就是彈出對話框顯示"red"。而在嚴格模式下,這個函數的this 的值是null,因
此在訪問null 的屬性時就會拋出錯誤。
8.其餘變化
嚴格模式還有其餘一些變化,但願讀者也能留意。首先是拋棄了with 語句。非嚴格模式下的with
語句可以改變解析標識符的路徑,但在嚴格模式下,with 被簡化掉了。所以,在嚴格模式下使用with
會致使語法錯誤。
//with 的語句用法//非嚴格模式:容許//嚴格模式:拋出語法錯誤with(location){ alert(href); }
嚴格模式也去掉了JavaScript 中的八進制字面量。以0 開頭的八進制字面量過去常常會致使不少錯
誤。在嚴格模式下,八進制字面量已經成爲無效的語法了。
//使用八進制字面量//非嚴格模式:值爲8//嚴格模式:拋出語法錯誤var value = 010;
ECMAScript 5 也修改了嚴格模式下parseInt()的行爲。現在,八進制字面量在
嚴格模式下會被看成以0 開頭的十進制字面量。例如:
//使用parseInt()解析八進制字面量//非嚴格模式:值爲8//嚴格模式:值爲10var value = parseInt("010");