JavaScript 中的 嚴格模式

劉春輝同學發表於2019-03-03

嚴格模式:使用嚴格模式的好處是可以提早知道程式碼中存在的錯誤,及時捕獲一些可能導致程式設計錯誤的 ECMAScript 行為。

嚴格模式的選擇使用

嚴格模式的編譯指示(pragma): "use strict";,支援嚴格模式的引擎會啟動這種模式,而不支援該模式的引擎就當遇到了一個未賦值的字串字面量,會忽略這個編譯指示。

  • 在全域性作用域中(函式外部)給出這個編譯指示,則整個指令碼都將使用嚴格模式。
  • 在函式作用域中給出這個編譯指示,則這個函式將使用嚴格模式
function test () {
    "use strict";
    ...
}
複製程式碼

嚴格模式的規範

變數

  1. 不允許意外建立全域性變數,給一個沒有宣告的變數賦值,那程式碼在執行時就會丟擲 ReferenceError
// 未宣告變數 
// 非嚴格模式:建立全域性變數 
// 嚴格模式:丟擲 ReferenceError
message = "Hello world! ";
複製程式碼
  1. 不能對變數呼叫 delete 操作符
//刪除變數 
//非嚴格模式:靜默失敗 
//嚴格模式:丟擲 ReferenceError
var color = "red";
delete color;
複製程式碼
  1. 嚴格模式下對變數名也有限制,不能使用 implements、interface、let、package、 private、protected、public、static 和 yield 識別符號作為變數名,使用以上識別符號作為變數名會導致語法錯誤。

物件

  1. 為只讀屬性賦值會丟擲 TypeError
  2. 對不可配置的(nonconfigurable)的屬性使用 delete 操作符會丟擲 TypeError
  3. 為不可擴充套件的(nonextensible)的物件新增屬性會丟擲 TypeError
  4. 使用物件字面量時,屬性名必須唯一
// 重名屬性 
// 非嚴格模式:沒有錯誤,以第二個屬性為準 
// 嚴格模式:丟擲語法錯誤
var person = {
    name: "Nicholas",
    name: "Greg"
};
複製程式碼

函式

  1. 嚴格模式要求命名函式的引數必須唯一
//重名引數 
//非嚴格模式:沒有錯誤,只能訪問第二個引數 
//嚴格模式:丟擲語法錯誤
function sum (num, num){
    // todo
}
複製程式碼
  1. 在非嚴格模式下,修改命名引數的值也會反映到arguments物件中,而嚴格模式下這兩個值是完全獨立的
//修改命名引數的值 
//非嚴格模式:修改會反映到 arguments 中 
//嚴格模式:修改不會反映到 arguments 中
function showValue(value) {
    value = "Foo";
    console.log(value); //"Foo" 
    console.log(arguments[0]); //非嚴格模式:"Foo",嚴格模式:"Hi"
}
showValue("Hi");
複製程式碼
  1. arguments.callee 和 arguments.caller,在非嚴格模式下,這兩個屬性一個引用函式本身,一個引用呼叫函式。而在嚴格模式下,訪問哪個屬性都會丟擲 TypeError
//訪問 arguments.callee 
//非嚴格模式:沒有問題 
//嚴格模式:丟擲 TypeError
function factorial(num){
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
}
var result=factorial(5);
複製程式碼
  1. 嚴格模式對函式名也做出了限制,不允許用implements、interface、let、package、private、protected、public、static 和 yield 作為函式名
  2. 只能在指令碼的頂級和在函式內部宣告函式
//在 if 語句中宣告函式 
//非嚴格模式:將函式提升到 if 語句外部 
//嚴格模式:丟擲語法錯誤
if (true){
    function doSomething(){
        // todo 
    }
}
複製程式碼

eval()

  1. 在嚴格模式中,它在包含上下文中不再建立變數或函式
//使用 eval()建立變數
//非嚴格模式:彈出對話方塊顯示 10
//嚴格模式:呼叫 alert(x)時會丟擲 ReferenceError
function doSomething(){
    eval("var x=10");
    alert(x);
}
複製程式碼
  1. 可以在 eval()中宣告變數和函式,但這些變數或函式只能在被求值的特殊作用域中有效,隨後就將被銷燬
"use strict";
var result = eval("var x=10, y=11; x+y");
alert(result);  // 21
複製程式碼

eval 和 arguments

嚴格模式已經明確禁止使用 eval 和 arguments 作為識別符號,也不允許讀寫它們的值。

// 把 eval 和 arguments 作為變數引用 
// 非嚴格模式: 沒問題,不出錯 
// 嚴格模式: 丟擲語法錯誤
var eval = 10;
var arguments = "Hello world!";
複製程式碼

抑制this

在非嚴格模式下使用函式的 apply()或 call()方法時,null 或 undefined 值會被轉換為全域性 物件。而在嚴格模式下,函式的 this 值始終是指定的值,無論指定的是什麼值。

// 訪問屬性
// 非嚴格模式: 傳入null, 函式的this值是全域性物件
// 嚴格模式: 丟擲錯誤,因為this的值為 null
var color = "red";
function displayColor(){
    alert(this.color);
}
displayColor.call(null);
複製程式碼

其他變化

  1. 非嚴格模式下的 with 語句能夠改變解析識別符號的路徑。嚴格模式下,with 被簡化掉了
//with 的語句用法
//非嚴格模式:允許
//嚴格模式:丟擲語法錯誤
with(location){
    alert(href);
}
複製程式碼
  1. 嚴格模式去掉了 JavaScript 中的八進位制字面量
//使用八進位制字面量 
//非嚴格模式:值為 8 
//嚴格模式:丟擲語法錯誤
var value = 010;
複製程式碼
  1. 嚴格模式下 parseInt()的行為,八進位制字面量在嚴格模式下會被當作以 0 開頭的十進位制字面量
//使用 parseInt()解析八進位制字面量 
//非嚴格模式:值為 8 
//嚴格模式:值為 10
var value = parseInt("010");
複製程式碼

相關文章