嚴格模式
JavaScript 的嚴格模式是使用受限制的 JavaScript 的一種方式,從而隱式地退出“草率模式”。嚴格模式不僅僅是一個子集:這種模式有意地與普通情形下的代碼有所區別。(MDN)
嚴格模式為 JavaScript
提供了一個更嚴格的運行環境。
開啟嚴格模式后,部分特性會發生改變,如 this
指向 window
的函數不再指向 window
,而是變成了 undefined
。
function Test() {
'use strict';
console.log('this:', this);
}
Test(); // 輸出:this: undefined
1. 開啟嚴格模式
1.1 對單個 script 標簽或者 js 文件開啟嚴格模式
單個 js 文件或者 script 標簽的嚴格模式,可以通過在所有代碼執行前加上 'use strict'
字符串開啟。
'use strict';
function Test() {
console.log('this:', this);
}
Test(); // 輸出:this: undefined
1.2 對一個函數開啟嚴格模式
在函數頂端協商 'use strict'
字符串,就可以打開整個函數的嚴格模式。
function testWith() {
'use strict';
var person = {
name: '鴿子天王',
age: 12,
};
var age = 11;
with (person) {
console.log(name);
console.log(age);
}
}
testWith();
在嚴格模式下是不提供 with
語句的調用的,所以這里會爆 Strict mode code may not include a with statement
錯誤。
2. 嚴格模式的規范
2.1 禁止使用 with
在嚴格模式下是禁止使用 with 語句的。
'use strict';
var person = {
name: '鴿子巨星',
};
with (person) {
console.log(name);
}
2.2 變量必須被聲明
在嚴格模式下,變量必須被聲明才能使用,否則會報錯。
// 非嚴格模式下
number = 1;
console.log(number); // 輸出:1
// 嚴格模式下
'use strict';
number = 1; // 報錯:ReferenceError: number is not defined
2.3 eval 會創建自己的作用域
非嚴格模式下的 eval 作用域是其本身所在的作用域,而嚴格模式下,eval 執行過程中會創建一個新的作用域,并在結束后銷毀。
// 非嚴格模式下
var number = 1;
eval('var number = 3; console.log(number)'); // 輸出:3
console.log(number); // 輸出:3
// 嚴格模式下
'use strict';
var number = 1;
eval('var number = 3; console.log(number)'); // 輸出:3
console.log(number); // 輸出:1
2.4 函數的 arguments 不能被修改
在非嚴格模式下,函數的 arguments
可以被重新賦值,在嚴格模式下,做賦值操作會報錯。
function fn() {
console.log(arguments);
arguments = 1;
console.log(arguments);
}
fn(1, 2, 3);
'use strict';
function fn() {
console.log(arguments);
arguments = 1;
console.log(arguments);
}
fn(1, 2, 3);
2.5 函數的 this 規則有些變化
在 this
章節中討論了不同情況的指向,其中有一種情況函數的 this
是指向 window 的。
在嚴格模式中,這種情況下的 this
會變成 undefined
。
function testThis() {
console.log(this);
}
testThis();
// 嚴格模式下
'use strict';
function testThis() {
console.log(this);
}
testThis();
2.6 caller 與 arguments.callee 被禁用
arguments.caller
可以獲取到調用當前函數的函數的引用(該屬性已經被標準廢棄,不再使用了)。
arguments.callee
則可以獲取到當前函數的引用。
這兩個屬性在嚴格模式下都被禁用。
function fn1() {
console.log(arguments.callee === fn1);
}
fn1();
'use strict';
function fn1() {
console.log(arguments.callee === fn1);
}
fn1();
2.7 刪除 configurable 為 false 的屬性時報錯
在非嚴格模式下,這種情況會直接忽略。
var obj = {};
Object.defineProperty(obj, 'prop', {
configurable: false,
value: 1,
});
console.log(obj);
delete obj.prop;
console.log(obj);
'use strict';
var obj = {};
Object.defineProperty(obj, 'prop', {
configurable: false,
value: 1,
});
console.log(obj);
delete obj.prop;
console.log(obj);
2.8 修改 writable 為 false 的屬性時會報錯
在非嚴格模式下,這種情況會直接忽略。
var obj = {};
Object.defineProperty(obj, 'prop', {
writable: false,
value: 1,
});
console.log(obj.prop);
obj.prop = 2;
console.log(obj.prop);
'use strict';
var obj = {};
Object.defineProperty(obj, 'prop', {
writable: false,
value: 1,
});
console.log(obj.prop);
obj.prop = 2;
console.log(obj.prop);
2.9 禁止書寫八進制的字面量
八進制的表示是在數字前面加一個 0
,但其實 ECMAScript
標準中并沒有這種表示法。
在 ES6 中提供了八進制數的表示方式,即在數字前加上 0o
前綴。
在嚴格模式下是禁止使用 0
前綴表示的八進制字面量的。
// 非嚴格模式中
var num = 010;
console.log(num); // 輸出:8
// 嚴格模式下
'use strict';
var num = 010;
console.log(num); // 輸出:8
2.10 新增了一些不能作為變量的關鍵字
許多關鍵字在非嚴格模式下是可以當作變量名的。
var yield = 1;
console.log(yield);
'use strict';
var yield = 1;
console.log(yield);
根據 MDN
提供的內容,保留字有:
- implements
- interface
- let
- package
- private
- protected
- public
- static
- yield
3. 小結
對嚴格模式大多數需要注意的是他帶來的一些語法上的改變,特別是有些寫法,在之前是不會報錯的,開啟嚴格模式后就會報錯,如果沒有進行錯誤處理,就會導致程序的中斷。
以上對嚴格模式下的改變不一定是全部,可以參考 MDN 的文檔。