嚴格模式(Strict Mode)是 ES5 的一個功能,它讓 JavaScript 的行為更好,也以不同的方式改變了 JavaScript 語言的語義。了解 JavaScript 的嚴格模式和「普通」JavaScript(通常稱為鬆散模式)之間的主要區別非常重要。

嚴格模式主要移除了 ES3 中尚可使用但自 ES5 起已被棄用的功能(由於向後相容性需求的緣故,這些功能並未被刪除)。

如何啟用嚴格模式

嚴格模式是可選的。對於 JavaScript 中的每個破壞性更改,我們不能更改語言的默認行為,否則會破壞大量現有的 JavaScript 代碼。JavaScript 在確保 1996 年的 JavaScript 代碼仍然運作正常方面非常注重,這是它成功的原因之一。

因此,我們需要使用 'use strict' 指令來啟用嚴格模式。

您可以將它放在文件的開頭,從而將其應用於文件中的所有代碼:

'use strict'

const name = 'Flavio'
const hello = () => 'hey'

//...

您還可以通過將 'use strict' 放在函數體的開頭,為個別函數啟用嚴格模式:

function hello() {
 'use strict'

 return 'hey'
}

這在處理舊代碼時很有用,當您無法花時間進行測試或沒有信心在整個文件中啟用嚴格模式時。

嚴格模式中的變化

意外的全局變數

如果您將值賦給未聲明的變數,JavaScript默認會在全局對象上創建該變數:

;(function() {
 variable = 'hey'
})()(() => {
 name = 'Flavio'
})()

variable //'hey'
name //'Flavio'

在啟用嚴格模式後,如果您試圖執行上述操作,將會引發一個錯誤:

;(function() {
 'use strict'
 variable = 'hey'
})()(() => {
 'use strict'
 myname = 'Flavio'
})()

Variable not defined

賦值錯誤

JavaScript 會在某些轉換錯誤時默默忽略這些錯誤。

在嚴格模式下,這些默默錯誤現在會引發錯誤:

const undefined = 1(() => {
 'use strict'
 undefined = 1
})()

與此相同的情況還適用於 Infinity、NaN、evalarguments 等。

在 JavaScript 中,您可以通過使用以下方式將對象的屬性設置為不可寫:

const car = {}
Object.defineProperty(car, 'color', { value: 'blue', writable: false })

在鬆散模式下,您可以覆蓋這個值,而在嚴格模式下則不允許:

對於 getter 屬性也是如此:

const car = {
 get color() {
 return 'blue'
 }
}
car.color = 'red'(
 //ok

 () => {
 'use strict'
 car.color = 'yellow' //TypeError: Cannot set property color of #<Object> which has only a getter
 }
)()

在鬆散模式下,可以擴展一個不可擴展的對象:

const car = { color: 'blue' }
Object.preventExtensions(car)
car.model = 'Fiesta'(
 //ok

 () => {
 'use strict'
 car.owner = 'Flavio' //TypeError: Cannot add property owner, object is not extensible
 }
)()

(參見Object.preventExtensions()

此外,在鬆散模式下,可以在原始值上設置屬性,不會引發錯誤,但也不會做任何操作:

true.false = ''(
 //''
 1
).name =
 'xxx' //'xxx'
var test = 'test' //undefined
test.testing = true //true
test.testing //undefined

嚴格模式在所有這些情況下都會報錯:

;(() => {
 'use strict'
 true.false = ''(
 //TypeError: Cannot create property 'false' on boolean 'true'
 1
 ).name =
 'xxx' //TypeError: Cannot create property 'name' on number '1'
 'test'.testing = true //TypeError: Cannot create property 'testing' on string 'test'
})()

刪除錯誤

在鬆散模式下,如果您嘗試刪除不可刪除的屬性,JavaScript 會返回 false;而在嚴格模式下,它會引發 TypeError:

delete Object.prototype(
 //false

 () => {
 'use strict'
 delete Object.prototype //TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
 }
)()

具有相同名稱的函數參數

在普通函數中,可以有重複的參數名稱:

(function(a, a, b) {
 console.log(a, b)
})(1, 2, 3)
//2 3


(function(a, a, b) {
 'use strict'
 console.log(a, b)
})(1, 2, 3)
//Uncaught SyntaxError: Duplicate parameter name not allowed in this context

請注意,箭頭函數在此情況下始終引發 SyntaxError

((a, a, b) => {
 console.log(a, b)
})(1, 2, 3)
//Uncaught SyntaxError: Duplicate parameter name not allowed in this context

八進制語法

在嚴格模式下,八進制語法被禁用。默認情況下,將 0 放在與八進制數字格式相容的數字之前,會使其(有時令人困惑地)被解釋為八進制數字:

(() => {
 console.log(010)
})()
//8

(() => {
 'use strict'
 console.log(010)
})()
//Uncaught SyntaxError: Octal literals are not allowed in strict mode.

您仍然可以使用 0oXX 語法在嚴格模式下啟用八進制數字:

;(() => {
 'use strict'
 console.log(0o10)
})()
//8

刪除 with

嚴格模式禁用了 with 關鍵字,以消除一些邊界情況,並允許更多編譯器級別的優化。