隨着WebApp日新月異的發展,Javascript寫的WebApp規模越來月龐大,好比典型的表明產品騰訊WebQQ、HTML5遊戲等等,Javascript愈來愈須要大量的開發人員多多人協做開發。同時HTML五、CSS3等新技術和NodeJs項目的高速發展,這幾年JavaScript語言藉着各類新API陸續被運用到從移動設備到服務器的多個」新領域」中。javascript
但JavaScript語言自身因爲ECMAScript第四版被放棄而一直沒有多少改進。和借HTML5之名過分宣傳的各類新API相比,語法層面經過嚴格模式(Strict Mode)進行的改進幾乎能夠用鮮爲人知來形容。學習瞭解嚴格模式以後,就算不立刻進行實踐,也會讓咱們對JavaScript中壞氣味的一方面有更清晰的認識,從而幫助咱們寫出更好的代碼。
下面的內容翻譯自It’s time to start using JavaScript strict mode,做者Nicholas C.Zakas參與了YUI框架的開發,並撰寫了多本前端技術書籍,在我看過關於JavaScript嚴格模式的入門介紹文章中,這篇是寫得最好的。html
ECMAScript5中引入的嚴格模式,經過讓JavaScript運行環境對一些開發過程當中最多見和不易發現的錯誤作出和當前不一樣的處理,來讓開發者擁有一個」更好」的JavaScript語言。很長一段時間內,因爲只有Firefox支持嚴格模式,我曾對嚴格模式表示懷疑。但到了今天,全部主流的瀏覽器都在他們的最新版本中支持了嚴格模式(包括IE10,Opera12和Android4,IOS5)是時候開始使用嚴格模式了。前端
嚴格模式爲JavaScript引入了不少變化,我把他們分爲兩類(明顯的和細微的)。細微改進的目標是修復當前JavaScript中的一些細節問題,對於這些問題我不在這裏進行深刻介紹;若是你有興趣,請閱讀Dmitry Soshnikov撰寫的精彩文檔ECMA-262-5 in Detail Chapter 2 Strict Mode。 我在這裏主要介紹嚴格模式引入的明顯變化,那些在你使用嚴格模式前應該知道的概念和那些對你幫助最大的改變。java
在開始學習具體特性前,請記住嚴格模式的一大目標是讓你能更快更方便的調試。運行環境在發現問題時顯性的拋出錯誤比默不作聲的失敗或怪異行事(未開啓嚴格模式的JavaScript運行環境常常這樣)要好。嚴格模式會拋出更多錯誤,但這是好事,由於這些錯誤會喚起你注意並修復不少之前很難被發現的潛在問題。web
首先,嚴格模式中去除了with語句,包含with語句的代碼在嚴格模式中會拋出異常。因此使用嚴格模式的第一步:確保你的代碼中沒有使用with。express
// 在嚴格模式中如下JavaScript代碼會拋出錯誤 with (location) { alert(href); }
其次,局部變量在賦值前必須先進行申明。在啓用嚴格模式以前,爲一個未申明的局部變量複製時會自動建立一個同名全局變量。這是Javacript程序中最容易出現的錯誤之一, 在嚴格模式中嘗試這麼作時會有顯性的異常拋出。瀏覽器
// 嚴格模式下會拋出異常 (function() { someUndeclaredVar = "foo"; }());
嚴格模式中另外一個重要的變化是函數中未被定義或爲空( null or undefined)的this不在默認指向全局環境(global)。這會形成一些依賴函數中默認this行爲的代碼執行出錯,例如:安全
window.color = "red"; function sayColor() { alert(this.color); } // 在strict模式中會報錯, 若是不在嚴格模式中則提示 「red" sayColor(); // 在strict模式中會報錯, 若是不在嚴格模式中則提示 「red" sayColor.call(null);
this在被賦值以前會一直保持爲undefined,這意味着當一個構造函數在執行時,若是以前沒有明確的new關鍵詞,會拋出異常。服務器
function Person(name) { this.name = name; } //在嚴格模式中會報錯 var me = Person("Nicholas");
在上面的代碼中,Person構造函數運行時由於以前沒有new,函數中的this會保留爲undefined, 因爲你不能爲undefined設置屬性,上面的代碼會拋出錯誤。 在非strict模式環境中,沒有被複制的this會默認指向window全局變量,運行的結果將是意外的爲window全局變量設置name屬性。框架
當編寫大量代碼時,對象屬性和函數參數很容易一不當心被設置成一個重複的名字。嚴格模式在這種狀況下會顯性的拋出錯誤
//重複的變量名,在嚴格模式下會報錯 function doSomething(value1, value2, value1) { //code } //重複的對象屬性名,在嚴格模式下會報錯: var object = { foo: "bar", foo: "baz" };
以上的代碼在嚴格模式中都會被認爲是語法錯誤而在執行前就讓你能獲得提示。
雖然eval()語句最終沒有被移除,但在嚴格模式中仍然對它進行了一些改進。最大的改變是在eval()中執行的變量和函數申明不會直接在當前做用域中建立相應變量或函數,例如:
(function() { eval("var x = 10;"); // 非嚴格模式中,alert 10 // 嚴格模式中則因x未被定義而拋出異常, alert(x); }());
任何在eval()執行過程當中建立的變量或者函數保留在eval()中。但你能明確的從eval()語句的返回值來獲取eval()中的執行結果,例如:
(function() { var result = eval("var x = 10, y = 20; x + y"); // 在strict或非strict模式中都能正確的運行餘下的語句.(resulst爲30) alert(result); }());
ECMAScript5中還引入爲對象的特定屬性設爲只讀,或讓整個對象不可修改的能力。 但在非嚴格模式中,嘗試修改一個只讀屬性只會默不作聲的失敗。 在你和一些瀏覽器原生API打交道過程當中,你極可能遇到這種狀況。嚴格模式會在這種狀況下明確的拋出異常,提醒你修改這個屬性是不被容許的。
var person = {}; Object.defineProperty(person, "name" { writable: false, value: "Nicholas" }); // 在非嚴格模式時,沉默的失敗,在嚴格模式則拋出異常. person.name = "John";
上面的例子中,name屬性被設爲只讀,非嚴格模式中執行對name屬性的修改不會引起報錯,但修改不會成功。但嚴格模式則會明確的拋出異常。
NOTE: 強烈建議你在使用任何ECMAScript屬性特性指定時開啓嚴格模式。
在現代瀏覽器中開啓嚴格模式很是容易,只須要在JavaScript代碼中出現如下指令便可
"use strict";
雖然看上去上面的代碼僅僅只是未賦予某個變量的字符串,它實際上起到指示JavaScript引擎切換到嚴格模式的做用(不支持嚴格模式的瀏覽器會忽略以上代碼,不會對後續的執行產生任何影響)。雖然你能把這個指令做用到全局或某個函數中,但這裏仍是要提醒,不要在全局環境下啓用嚴格模式。
// 請不要這麼使用 "use strict"; function doSomething() { // 這部分代碼會運行於嚴格模式 } function doSomethingElse() { // 這部分代碼也會運行於嚴格模式 }
雖然上面的代碼看起來不算一個大問題。但當你不負責維護頁面中引入的所有代碼時,這樣使用strict模式會讓你面臨因爲第三方代碼沒有爲嚴格模式作好準備而引起的問題。
所以,最好把開啓嚴格模式的指令做用於函數中,例如:
function doSomething() { "use strict"; // 這個函數中的代碼將會運行於嚴格模式 } function doSomethingElse() { // 這個函數中代碼不會運行於嚴格模式 }
若是你想讓嚴格模式在不止一個函數中開啓,請使用當即執行函數表達式 (immediately-invoked function expression ,IIFE):
(function() { "use strict"; function doSomething() { // 這個函數運行於嚴格模式 } function doSomethingElse() { // 這個函數一樣運行於嚴格模式 } }());
我強烈建議你從如今開始就啓用JavaScript嚴格模式,它能幫你發現代碼中不曾注意到的錯誤。不要在全局環境中啓用,但你能儘可能多的使用IIFE(當即執行函數表達式)來把嚴格模式做用到多個函數範圍內。一開始,你會遇到以前不曾碰到過的錯誤提示,這是正常的。當啓用嚴格模式後,請確保在支持的瀏覽器中作了測試,以發現新的潛在問題。必定不要僅僅在代碼中添加一行」use strict」就假定餘下的代碼能正常工做。最後,請在嚴格模式下開始編寫更好的代碼。