1. 程式人生 > >JavaScript嚴謹模式(Strict Mode)

JavaScript嚴謹模式(Strict Mode)

下面的內容翻譯自It’s time to start using JavaScript strict mode,作者Nicholas C.Zakas參與了YUI框架的開發,並撰寫了多本前端技術書籍,在我看過關於JavaScript嚴格模式的入門介紹文章中,這篇是寫得最好的。

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

嚴格模式能起到什麼作用?

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

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

去除WITH關鍵詞

首先,嚴格模式中去除了with語句,包含with語句的程式碼在嚴格模式中會丟擲異常。所以使用嚴格模式的第一步:確保你的程式碼中沒有使用with。

// 在嚴格模式中以下JavaScript程式碼會丟擲錯誤
with (location) {
    alert(href);
}

防止意外為全域性變數賦值

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

// 嚴格模式下會丟擲異常
(function
() { someUndeclaredVar = "foo"; }());

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

嚴格模式中另一個重要的變化是函式中未被定義或為空( 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()語句最終沒有被移除,但在嚴格模式中仍然對它進行了一些改進。最大的改變是在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”就假定餘下的程式碼能正常工作。最後,請在嚴格模式下開始編寫更好的程式碼。

注:

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

相關推薦

JavaScript嚴謹模式(Strict Mode)

下面的內容翻譯自It’s time to start using JavaScript strict mode,作者Nicholas C.Zakas參與了YUI框架的開發,並撰寫了多本前端技術書籍,在我看過關於JavaScript嚴格模式的入門介紹文章中,這篇是寫得最好的。 ECMAScript5中引入的嚴

Javascript 嚴格模式(strict mode)詳解

eval ref 條件 ssa for this關鍵字 表示法 ocs 行為 Javascript 嚴格模式詳解 一、概述 除了正常運行模式,ECMAscript 5添加了第二種運行模式:"嚴格模式"(strict mode)。顧名思義,這種模式使得Jav

JavaScript嚴格模式 "use strict"

1.在嚴格模式下,變數必須顯示宣告(var/let/const),直接給變數賦值,不會隱式建立全域性變數 (function(){ //非嚴格模式 a = 10; console.log(a); //10 })(); (function(){ "use strict"

JavaScript嚴格模式(use strict

說明 對於小白們來說(也包括我)也可能都知道JavaScript的變數可以不用宣告就可以直接使用,但是在(ECMAScript5)中新增了嚴格模式,即JavaScript嚴格模式(strict mode)即在嚴格的條件下執行。 支援嚴格模式的瀏

Javascript 嚴格模式詳解 strict 模式

今天使用jquery.validate.js 發現如下錯誤:0x800a13b3 - JavaScript 執行時錯誤: strict 模式下不允許訪問函式或引數物件的“caller”屬性 查詢資料如下: 一、概述 除了正常執行模式,ECMAscript 5添加了第二種執行

JavaScript設計模式:一、面向對象編程

this 依賴 人在 turn obj log javascrip 體會 創建 JavaScript面向對象編程 眾所周知,JS作為一門腳本語言,由於其設計者在設計JS的時候,也僅僅用了很少的時間就完成了JS這門語言的創建,JS雖然擁有著腳本語言的優勢,但是JS也存在著

JavaScript設計模式:一、面向對象編程(第二節)

得到 調用 帶來 方式 get 特權 style 方法封裝 面向對象 一、封裝 面向對象編程思想其中的一個特點就是封裝,通俗的講法就是把需要的功能方向在一個對象裏。遺憾的是,對於JS這種解釋性的弱類型語言沒有經典強類型語言中那樣通過class等關鍵字實現類的封裝方法,j

JavaScript設計模式:一、面向對象編程(第三節)

設置 style 擁有 ray 進行 如果 eat gree 而在 一、繼承 js並沒有繼承這一個現有的機制,所以我們所說的繼承是通過JS本身的機制去實現的。 1、類式繼承 1 // 類式繼承 2 3 // 父類 4 function SuperClas

javascript設計模式詳解之命令模式

這一 clas 例子 別了 logs 操作 book 技術 概念   每種設計模式的出現都是為了彌補語言在某方面的不足,解決特定環境下的問題。思想是相通的。只不過不同的設計語言有其特定的實現。對javascript這種動態語言來說,弱類型的特性,與生俱來的多態性,導致某些設

javascript設計模式》讀書筆記二(封裝和隱藏信息)

mil del ims 是你 信息 私有屬性 bsp delet urn 1.為什麽要封裝和信息隱藏 做過編程的朋友們知道“耦合”這個詞。事實上封裝的效果就是為了解耦,讓類和類之間沒有太多的聯系,防止某一天改動某一類的時候,產生“多米骨諾牌效應”。 我們能夠把信息隱

javascript設計模式-單例模式

空間 spa 靜態變量 通過 script 無法 單例 onf 訪問 單例模式,是創建型設計模式的一種,又被稱為單體模式,是只允許實例化一次的對象類。有時也用來規劃一個命名空間。 1 var Util = { 2 getName: function () {

JavaScript 設計模式入門和框架中的實踐 http://www.codeceo.com/article/javascript-design-pattern.html

{} static log block 抽象 listener args assign ack 在編寫JS代碼的過程中,運用一定的設計模式可以讓我們的代碼更加優雅、靈活。 下面筆者就結合諸如redux的subscribe、ES6的class、vue裏面的$dispatch、

Javascript設計模式與開發實踐詳解(二:策略模式) http://www.jianshu.com/p/ef53781f6ef2

的人 思想 ram gis pan pro msg have 改變 上一章我們介紹了單例模式及JavaScript惰性單例模式應用這一次我主要介紹策略模式策略模式是定義一系列的算法,把它們一個個封裝起來,並且讓他們可以互相替換。比方說在現實中很多時候也有很多途徑到達同一個

JavaScript設計模式_03_代理模式

col img 文章 timer argument 設計 jpg 朋友 進行 代理模式是非常常見的模式,比如我們使用的VPN工具,明星的經紀人,都是代理模式的例子。但是,有人會疑問,明明可以直接訪問對象,為什麽中間還要加一個殼呢?這也就說到了代理模式的好處。在我看來,代理模

javascript設計模式

back inner names method build php ids opacity mon 單例模式(Singleton) 工廠模式(Factory) 橋接模式(Bridge) 組合模式(Composite) 門面模式(Facade) 適配器模

JavaScript設計模式_13_狀態模式

設計 .proto doc back console 當前 中一 n) 寫代碼 狀態模式是一種根據事物內部狀態的改變,從而改變事物行為的一種模式。 /** * pre:狀態模式 */ //---------- 示例1 ---------------- /** * 模

javaScript 設計模式之中介者模式示例

ava 設計模式 cti rip type color function div this 飛機把註冊信息放到鐵塔裏,發送數據到鐵塔,報告其它的飛機一些信息。 var feiji = function( name ){ this.name = name; }

javascript 設計模式 -- 發布/訂閱模式

length 內部 設計模式 name 不能 data lis 設計 class 直接上代碼: index.html : <!DOCTYPE html> <html lang="en"> <head> <meta charset

JavaScript設計模式-6.封裝

弊端 單元 類的定義 相同 return 驗證 demo 完成 問題: 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"

JavaScript設計模式-3.原型模式

掛載 r+ eof style 數據 默認 per blog script 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"&g