ES5嚴格模式(Strict mode)


嚴格模式(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)。

 

相關:

Mozilla strict mode

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/

JavaScript中delete操作符不能刪除的對象

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM