嚴格模式(Strict mode)是由ECMA-262規范定義的新興JavaScript標准,第五版發布於2009年12月。旨在改善錯誤檢查功能並且標識可能不會延續到未來JavaScript版本的腳本。ES5嚴格模式是限制性更強的JavaScript變體,它與常規JavaScript的語義不同,其分析更為嚴格。
目前,除了IE6-9,其它瀏覽器均已支持ES5嚴格模式。
一、嚴格模式的使用
嚴格模式的使用很簡單,只有在代碼首部加入字符串 "use strict"。有兩種應用場景,一種是全局模式,一種是局部模式。
1)全局模式
'use strict' var globalVal = 100 console.log(globalVal)
執行后輸出了100,與非嚴格模式沒什么區別。
2)局部模式
將"use strict"放到函數內的第一行,如下
function func() { 'use strict' var localVal = 200 console.log(localVal) } func()
執行后輸出了200,與非嚴格模式也沒用什么區別。
3)模塊模式
如果你想定義一個模塊或者一個小庫,自然采用一個匿名函數自執行是不錯的選擇
~function() { "use strict"; // Define your library strictly... }();
“use strict” 的位置是很講究的,必須在首部。首部指其前面沒有任何有效js代碼。以下都是無效的,將不會觸發嚴格模式。
a)“use strict” 前有代碼
var width = 10 'use strict' globalVar = 100
b)“use strict” 前有個空語句都不行
; 'use strict' globalVar = 100
或
function func() { ; 'use strict' localVar = 200 }
或
function func() { ;'use strict' localVar = 200 }
當然,“use strict”前加注釋是可以的
// strict mode 'use strict' globalVar = 100
或
function func() { // strict mode 'use strict' localVar = 200 } func()
二、嚴格模式下的執行限制
上面舉的兩個例子,在嚴格模式中輸出與普通模式沒用什么區別。下面就不一樣了。
1)不使用var聲明變量嚴格模式中將不通過
我們知道JS是弱類型,寬松的語言。不使用var聲明的變量默認轉為全局變量。但在嚴格模式中將不允許,會報語法錯誤。
'use strict' globalVal = 100
執行,Firebug提示如下
又如全局的for循環
'use strict' for (i=0; i<5; i++) { console.log(i) }
這種寫法在非嚴格模式中很危險,i 會不小心溢出成為全局變量。但在嚴格模式中會報錯
局部模式
function func() { 'use strict' localVal = 200 console.log(localVal) } func()
執行,Firebug報錯
因此,嚴格模式中聲明變量務必記得加一個var。
2)任何使用'eval'的操作都會被禁止
'use strict' var obj = {} var eval = 3 obj.eval = 1 obj.a = eval for (var eval in obj) {} function eval() {} function func(eval) {} var func = new Function('eval')
Firebug報錯
3)eval作用域
JS中作用域有兩種,全局作用域和函數作用域。嚴格模式帶來了第三種作用域:eval作用域,如下
'use strict' var a = 10 eval('var a = 20; console.log(a)') console.log(a)
Firebug控制台依次輸出了20,10。eval是在全局模式下(非函數內)的,如果不加嚴格模式,此時修改的是全局的a。即輸出20,20。見 eval與window.eval的差別。
4)with被禁用
'use strict' with({a:1}) { }
Firebug報錯
5)caller/callee 被禁用
function func() { 'use strict' arguments.callee arguments.caller } func()
Firebug報錯
6)對禁止擴展的對象添加新屬性會報錯
'use strict' var obj = {} Object.preventExtensions(obj) obj.a = 1 // 報錯
Firebug報錯
7)刪除系統內置的屬性會報錯
'use strict' delete Object.prototype // 報錯 delete Function.prototype // 報錯
Firebug 報錯
8)delete使用var聲明的變量或掛在window上的變量報錯
'use strict' var obj = {a:1} window.a = 1 delete obj // 報錯 delete a // 報錯
Firebug報錯
9)delete不可刪除屬性(isSealed或isFrozen)的對象時報錯
'use strict' var obj = {a: 1} Object.seal(obj) delete obj.a
Firebug報錯
10)對一個對象的只讀屬性進行賦值將報錯
'use strict' var obj = {} Object.defineProperty(obj, 'a', {value: 1, writable: false}) obj.a = 2 // 報錯
Firebug報錯
11)對象有重名的屬性將報錯
'use strict' var obj = { a: 1, a: 2 }
Firebug報錯
而在非嚴格模式中,后面的屬性將覆蓋前面的屬性,即obj.a等於2。
12)函數有重名的參數將報錯
'use strict' function func(a, a) { alert(a) } func()
Firebug報錯
而在非嚴格模式中,后面的同名參數將覆蓋前面的。
13)八進制表示法被禁用
'use strict' var num = 022
Firebug報錯
14)arguments嚴格定義為參數,不再與形參綁定
先看非嚴格模式代碼
function func(a) { arguments[0] = 2 alert(a) // 2 } func(1)
func調用時傳參為1,函數內部通過arguments修改為2,此時alert的為修改后的2。 而在嚴格模式中則不能被修改,如下
'use strict' function func(a) { arguments[0] = 2 alert(a) // 1 } func(1)
顯示的嚴格的為傳入的1。
其實有點還有點復雜,如果alert的是arguments[0],實際在嚴格模式中仍然被修改為2了。如下
'use strict' function func(a) { arguments[0] = 2 alert(arguments[0]) // 2 } func(1)
可以參考下 僅Chrome中函數實參與形參發生關聯
15)函數必須聲明在頂層
我們知道函數聲明和函數表達式是兩個不同的概念。一般函數聲明都在最頂層,ES5前的JS寬松,你可以寫在if或for內(強烈鄙視這種寫法)。當然Firefox的解析方式與其他瀏覽器不同,見SJ9002。而在嚴格模式中這些寫法將直接報錯
'use strict' if (true) { function func1() { } // 語法錯誤 } for (var i = 0; i < 5; i++) { function func2() { } // 語法錯誤 }
Firebug報錯
16)ES5里新增的關鍵字不能當做變量標示符使用,如implements, interface, let, package, private, protected, public, static, yield
'use strict' var let = 10 var yield = 20
Firebug報錯
17)call/apply的第一個參數直接傳入不包裝為對象
'use strict' function func() { console.log(typeof this) } func.call('abcd') // string func.apply(1) // number
Firebug輸出如下
依次為"string","number"。而在非嚴格模式中call/apply將對值類型的"abcd",1包裝為對象后傳入,即兩次輸出都為"object"。
18)call/apply的第一個參數為null/undefined時,this為null/undefined
這里以call來示例
'use strict' function func() { console.log(this) } func.call(undefined) // undefined func.call(null) // null
Firebug輸出如下
依次是undefined,null。而非嚴格模式中則是宿主對象,瀏覽器里是window,node.js環境則是global。
19)bind的第一個參數為null/undefined時,this為null/undefined
bind是ES5給Function.prototype新增的一個方法,它和call/apply一樣在function上直接調用。它返回一個指定了上下文和參數的函數。當它的第一個參數為null/undefined時,情形和call/apply一樣,this也為null/undefined。
'use strict' function func() { console.log(this) } var f1 = func.bind(null) var f2 = func.bind(undefined) f1() // null f2() // undefined
而在非嚴格模式中輸出的都是window(或global)。
相關:
http://msdn.microsoft.com/library/br230269.aspx
http://java-script.limewebs.com/strictMode/test_hosted.html
http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/
http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/