JavaScript的嚴格模式

1、前言

ES5最先引入了嚴格模式的概念。經過嚴格模式,能夠在函數內部選擇較爲嚴格的全局或局部的錯誤條件檢測。使用嚴格模式的好處是,能夠提前地發現函數內部存在的錯誤以及編譯中產生的錯誤。 支持嚴格模式的瀏覽器包括IE10+、FireFox4+、Safari5.1+和Chromejavascript


2、選擇使用

使用編譯指示,實際上就是一個字符串:"use strict"; 若是在全局做用域中(函數外部)使用這個編譯指示,則整個腳本都將使用嚴格模式。 也就是說,若是把帶有嚴格模式的腳本放在其餘文件中,那麼這個文件下的JS代碼也會處於嚴格模式下。 也能夠在函數中打開嚴格模式,java

function fn() {
 "use strict";
    // more codes
}
複製代碼

3、變量

在嚴格模式下,何時建立變量以及怎麼建立變量都是有限制的。瀏覽器

1. 必須聲明

不容許意外建立全局變量,必需要有一個聲明。app

var msg = "Hello!";
複製代碼

2. 不能使用delete操做符

不能對變量調用delete操做符。在非嚴格模式下會靜默失敗,可是不會報錯。而在嚴格模式下會報錯。函數

3. 變量名不能使用保留字

嚴格模式下,不能使用implements、interface、let、package、private、protected、public、static、yield等保留字做爲變量名。ui


4、對象

在非嚴格模式下,操做對象時有些錯誤會靜默失敗,而在嚴格模式下就會報錯。 如下狀況時操做對象會報錯:this

  • 爲只讀屬性賦值會拋出TypeError;
  • 對不可配置的屬性使用delete操做符會拋出TypeError;
  • 爲不可擴展的對象添加屬性會拋出TypeError。

另外嚴格模式下,在經過對象字面量形式來聲明對象時,屬性名必須惟一,不然會報錯。spa

var person = {
    name: 'Knight',
    name: 'Bill'
} // Error
複製代碼

5、函數

1. 參數必須惟一

function add(a, a) { 
// dosomething 
}
複製代碼

解析: 上面這段函數聲明在非嚴格模式下是不會報錯的。 嚴格模式下,經過參數名只能訪問第二個參數,第一個參數必須經過**arguments對象(形參列表)**進行訪問。code

2. arguments對象的命名參數

在嚴格模式下,arguments對象的行爲和非嚴格模式是有區別的。 在非嚴格模式下,修改命名參數的值會反映到arguments對象中,可是在嚴格模式下這兩個值是相互獨立的。cdn

function showName(name) {
    name = 'Mike',
    console.log(name); // 'Mike'
    console.log(arguments[0]); // 非嚴格模式:'Mike'; 嚴格模式: 'Bill'
}
showName('Bill');
複製代碼

解析:在調用函數時,首先會傳入實參值'Bill',並寫入arguments對象中。 在非嚴格模式下,函數內部將name值從新賦值爲'Mike',所以arguments[0]的值也被同時修改成'Mike'。 而在嚴格模式下,arguments[0]的值依然是'Bill'。

3. arguments對象的callee和caller

在非嚴格模式下,這兩個屬性一個引用函數自己,一個引用調用函數。 而在嚴格模式下,這兩個屬性被淘汰,使用時均會報錯。

// 求一個階乘
function fn(num) {
    if(num <= 1) {
        return 1;
    }else {
        return num * arguments.callee(num-1);
    }
}
console.log(fn(3)); // 3! = 6
複製代碼

解析: 這是一個求階乘的函數,在非嚴格模式下,調用函數時,可用arguments.callee()來調用函數自己,從而實現函數功能。 而在嚴格模式下則會報錯。

4. 函數名不容許用保留字

嚴格模式下,不能使用implements、interface、let、package、private、protected、public、static、yield等保留字做爲函數變量名。

5. 禁止不在腳本或者函數層面上的函數聲明

在嚴格模式下,只能在腳本的頂級和在函數內部聲明函數。也就是說,在if語句/for語句中,聲明函數是會報錯的。

"use strict";
if (true) {
  function f() { } // !!! 語法錯誤
  f();
}

for (var i = 0; i < 5; i++) {
  function f2() { } // !!! 語法錯誤
  f2();
}

function baz() { // 合法
  function eit() { } // 一樣合法
}
複製代碼

6、eval()

eval()在包含上下文中再也不建立變量和函數。

function fn() {
    eval("var x = 123;");
    console.log(x);
}
fn();
複製代碼

解析:上述代碼在嚴格模式下是會報錯的(ReferenceError),而在非嚴格模式下正常運行。


7、eval與arguments

嚴格模式不容許使用eval和arguments做爲標識符,也不容許讀寫它們的值。

var eval = 'hello';
var arguments = 'world';
複製代碼

解析:這在非嚴格模式下是能夠解析運行的,可是在嚴格模式下會報錯。 所以,不能將它們用做標識符,如下幾種狀況均會拋出語法錯誤:

  • 使用var聲明
  • 賦予另外一個值
  • 嘗試修改包含的值,如使用++
  • 用做函數名
  • 用做命名的函數參數
  • 在try-catch語句中用做例外名

8、抑制this

在非嚴格模式下使用apply()或者call()方法時,null和undefined值會轉換爲全局對象。 而在嚴格模式下,函數的this值始終是指定的值,不管指定的是什麼值。

var color = "red";
function displayColor() {
    console.log(this.color);
}
displayColor.call(null);
複製代碼

解析: 在非嚴格模式下,displayColor.call()中傳入了null,那麼此時函數的this是全局對象,所以會打印出red。 而在嚴格模式下,這個函數的this就是null,所以在訪問null的屬性時會報錯。


9、其餘變化

1. 拋棄with語句

非嚴格模式下,with語句能夠改變解析標識符的路徑,可是在嚴格模式下,with被簡化,會報錯。

with(location) {
    alert(href);
}
複製代碼

2. 拋棄八進制字面量

以0開頭的八進制字面量過去常常會致使不少錯誤。 所以,在嚴格模式下,八進制字面量已經被拋棄。

var val = 010;
複製代碼

3. parseInt()的變化

在ES5標準的嚴格模式下,八進制字面量會被當作以0開頭的十進制字面量。

var val = parseInt("010");
console.log(val); // 10
複製代碼

10、思惟導圖

相關文章
相關標籤/搜索