深入理解javascriptstrict 模式(Strict Mode),javascriptstrict

來源:互聯網
上載者:User

深入理解javascriptstrict 模式(Strict Mode),javascriptstrict

ECMAScript5中引入的strict 模式,通過讓JavaScript運行環境對一些開發過程中最常見和不易發現的錯誤做出和當前不同的處理,來讓開發人員擁有一個”更好”的JavaScript語言。很長一段時間內,由於只有Firefox支援strict 模式,我曾對strict 模式表示懷疑。但到了今天,所有主流的瀏覽器都在他們的最新版本中支援了strict 模式(包括IE10,Opera12和Android4,IOS5)是時候開始使用strict 模式了。

strict 模式能起到什麼作用?

strict 模式為JavaScript引入了很多變化,我把他們分為兩類(明顯的和細微的)。細微改進的目標是修複當前JavaScript中的一些細節問題,對於這些問題我不在這裡進行深入介紹;如果你有興趣,請閱讀Dmitry Soshnikov撰寫的精彩文檔ECMA-262-5 in Detail Chapter 2 Strict Mode。 我在這裡主要介紹strict 模式引入的明顯變化,那些在你使用strict 模式前應該知道的概念和那些對你協助最大的改變。

在開始學習具體特性前,請記住strict 模式的一大目標是讓你能更快更方便的調試。運行環境在發現問題時顯性的拋出錯誤比默不做聲的失敗或怪異行事(未開啟strict 模式的JavaScript運行環境經常這樣)要好。strict 模式會拋出更多錯誤,但這是好事,因為這些錯誤會喚起你注意並修複很多以前很難被發現的潛在問題。

去除WITH關鍵詞

首先,strict 模式中去除了with語句,包含with語句的代碼在strict 模式中會拋出異常。所以使用strict 模式的第一步:確保你的代碼中沒有使用with。

複製代碼 代碼如下:
// 在strict 模式中以下JavaScript代碼會拋出錯誤
with (location) {
    alert(href);
}

防止意外為全域變數賦值

其次,局部變數在賦值前必須先進行申明。在啟用strict 模式之前,為一個未申明的局部變數複製時會自動建立一個同名全域變數。這是Javacript程式中最容易出現的錯誤之一, 在strict 模式中嘗試這麼做時會有顯性的異常拋出。

複製代碼 代碼如下:
// strict 模式下會拋出異常
(function() {
    someUndeclaredVar = "foo";
}());

函數中的THIS不再預設指向全域

strict 模式中另一個重要的變化是函數中未被定義或為空白( null or undefined)的this不在預設指向全域環境(global)。這會造成一些依賴函數中預設this行為的代碼執行出錯,例如:

複製代碼 代碼如下:
window.color = "red";
function sayColor() {
    alert(this.color);
}
// 在strict模式中會報錯, 如果不在strict 模式中則提示 “red"
sayColor();
// 在strict模式中會報錯, 如果不在strict 模式中則提示 “red"
sayColor.call(null);

this在被賦值之前會一直保持為undefined,這意味著當一個建構函式在執行時,如果之前沒有明確的new關鍵詞,會拋出異常。

複製代碼 代碼如下:
function Person(name) {
    this.name = name;
}
//在strict 模式中會報錯
var me = Person("Nicholas");

在上面的代碼中,Person建構函式運行時因為之前沒有new,函數中的this會保留為undefined, 由於你不能為undefined設定屬性,上面的代碼會拋出錯誤。 在非strict模式環境中,沒有被複製的this會預設指向window全域變數,啟動並執行結果將是意外的為window全域變數設定name屬性。

防止重名

當編寫大量代碼時,對象屬性和函數參數很容易一不小心被設定成一個重複的名字。strict 模式在這種情況下會顯性的拋出錯誤

複製代碼 代碼如下:
//重複的變數名,在strict 模式下會報錯
function doSomething(value1, value2, value1) {
    //code
}
//重複的對象屬性名稱,在strict 模式下會報錯:
var object = {
    foo: "bar",
    foo: "baz"
};

以上的代碼在strict 模式中都會被認為是語法錯誤而在執行前就讓你能得到提示。

安全的 EVAL()

雖然eval()語句最終沒有被移除,但在strict 模式中仍然對它進行了一些改進。最大的改變是在eval()中執行的變數和函數申明不會直接在當前範圍中建立相應變數或函數,例如:

複製代碼 代碼如下:
(function() {
    eval("var x = 10;");
    // 非strict 模式中,alert 10
    // strict 模式中則因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中還引入為對象的特定屬性設為唯讀,或讓整個對象不可修改的能力。 但在非strict 模式中,嘗試修改一個唯讀屬性只會默不做聲的失敗。 在你和一些瀏覽器原生API打交道過程中,你很可能遇到這種情況。strict 模式會在這種情況下明確的拋出異常,提醒你修改這個屬性是不被允許的。

複製代碼 代碼如下:
var person = {};
Object.defineProperty(person, "name" {
    writable: false,
    value: "Nicholas"
});
// 在非strict 模式時,沉默的失敗,在strict 模式則拋出異常.
person.name = "John";

上面的例子中,name屬性被設為唯讀,非strict 模式中執行對name屬性的修改不會引發報錯,但修改不會成功。但strict 模式則會明確的拋出異常。

NOTE: 強烈建議你在使用任何ECMAScript屬性特性指定時開啟strict 模式。

如何使用?

在現代瀏覽器中開啟strict 模式非常容易,只需要在JavaScript代碼中出現以下指令即可

"use strict";
 

雖然看上去上面的代碼僅僅只是未賦予某個變數的字串,它實際上起到指示JavaScript引擎切換到strict 模式的作用(不支援strict 模式的瀏覽器會忽略以上代碼,不會對後續的執行產生任何影響)。雖然你能把這個指令作用到全域或某個函數中,但這裡還是要提醒,不要在全域環境下啟用strict 模式。

複製代碼 代碼如下:
// 請不要這麼使用
"use strict";
function doSomething() {
    // 這部分代碼會運行於strict 模式
}
function doSomethingElse() {
    // 這部分代碼也會運行於strict 模式
}

 
雖然上面的代碼看起來不算一個大問題。但當你不負責維護頁面中引入的全部代碼時,這樣使用strict模式會讓你面臨由於第三方代碼沒有為strict 模式做好準備而引發的問題。

因此,最好把開啟strict 模式的指令作用於函數中,例如:

複製代碼 代碼如下:
function doSomething() {
    "use strict";
    // 這個函數中的代碼將會運行於strict 模式
}
function doSomethingElse() {
    // 這個函數中代碼不會運行於strict 模式
}

 
如果你想讓strict 模式在不止一個函數中開啟,請使用立即執行函數運算式 (immediately-invoked function expression ,IIFE):

複製代碼 代碼如下:
(function() {
    "use strict";
    function doSomething() {
        // 這個函數運行於strict 模式
    }
    function doSomethingElse() {
        // 這個函數同樣運行於strict 模式
    }
}());

結論

我強烈建議你從現在開始就啟用JavaScriptstrict 模式,它能幫你發現代碼中未曾注意到的錯誤。不要在全域環境中啟用,但你能盡量多的使用IIFE(立即執行函數運算式)來把strict 模式作用到多個函數範圍內。一開始,你會遇到之前未曾碰到過的錯誤提示,這是正常的。當啟用strict 模式後,請確保在支援的瀏覽器中做了測試,以發現新的潛在問題。一定不要僅僅在代碼中添加一行”use strict”就假定餘下的代碼能正常工作。最後,請在strict 模式下開始編寫更好的代碼。

註:
這裡有各款瀏覽器對strict 模式支援情況的一個匯總。
可以在這個頁面對當前瀏覽器的strict 模式支援度進行測試。

strict 模式的優勢:

使JavaScript更牢固
1.      This不再被封裝,在normal mode下,this一直是對象。
2.      Fun.caller和fun.arguments即不是可以刪除的屬性,也不能被set或retrieved。
3.      Arguments.caller也是不可以刪除的屬性,也不能set或retrieved。

為將來的ECMAScript版本鋪平道路
1.      增加了下列保留字:implements, interface, let,package, private, protected, public, static和yield 。
2.      方法聲明應該放在指令碼或方法的最前面,不能放在if或for等語句中間。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.