ES5 規範之嚴格模式詳解

前言

ECMAScript 5 最先引入了 「嚴格模式」(strict mode)的概念。經過嚴格模式,能夠在函數內部存在的錯誤,及時捕獲一些可能致使編程錯誤的 ECMAScript 行爲。javascript

理解嚴格模式的規則很是重要,ECMAScript 的下一個版本將以嚴格模式爲基礎制定。支持嚴格模式的瀏覽器包括 IE10+、Firefox 4+、Safari 5.1+ 和 Chrome。java

嚴格模式的目的

  • 消除 JavaScript 語法的一些不合理、不嚴謹之處,減小一些怪異行爲
  • 消除代碼運行的一些不安全之處,保證代碼運行的安全
  • 提升編譯器效率,增長運行速度
  • 爲將來新版本的 JavaScript 作好鋪墊

嚴格模式的開啓

想要開啓嚴格模式,直接在做用域開始的位置寫上字符串 "use strict";編程

在全局模式下開啓:瀏覽器

"use strict";
複製代碼

在局部模式下開啓(在函數中打開嚴格模式):安全

function fn(){
 "use strict";
     // 其餘代碼
}
複製代碼

嚴格模式的規則(執行限制)

一、變量var:消除了僞全局變量

在嚴格模式下,何時建立變量以及怎麼建立變量都是有限制的。不容許意外建立全局變量(就是嚴格模式下消除了僞全局變量)。瞭解僞全局變量請閱讀【三分鐘帶你深刻理解 JavaScript 的函數做用域markdown

// 注意:(function(){})()是一個匿名函數
(function () { 
    a = 10;
    console.log(a);
})(); // 結果:10

(function () {
 "use strict";
    a = 10;
})();  // 報錯:ReferenceError: a is not defined
複製代碼

在非嚴格模式下,即便變量 a 前面沒有 var 關鍵字,即便沒有將它定義爲某個全局對象的屬性,也能將 a 建立爲僞全局變量使用。dom

在嚴格模式下,若是給一個沒有聲明的變量賦值,那代碼在執行的時候就會拋出錯誤 ReferenceError(引用錯誤)函數

二、對函數參數的要求:更爲嚴格

嚴格模式要求命名函數的參數必須惟一。post

// 非嚴格模式
(function () { 
    function foo(a ,a, b){
         console.log(a,b);
     }
    foo(1,2,3)
 })();  // 結果: 2 3

// 嚴格模式
 (function () { 
 "use strict";
     function foo(a ,a, b){
         console.log(a,b);
     }
     foo(1,2,3)
 })(); // 報錯:SyntaxError: Duplicate parameter name not allowed in this context
複製代碼

在非嚴格模式下,這個函數聲明不會拋出錯誤。經過參數名只能訪問重複參數的第二個參數,要訪問第一個重複參數,必須經過 arguments 對象。ui

在嚴格模式下,上面函數參數的不規範會拋出 SyntaxError(對象表明嘗試解析語法上不合法的代碼的錯誤)

三、實參形參 和 arguments 的分離

在嚴格模式下,arguments對象的行爲有所不一樣。

在非嚴格模式下,修改命名參數的值也會反映到 arguments 對象中,而嚴格模式下這兩個值是徹底獨立的。

// 非嚴格模式
// arguments 會受到 形參賦值的影響;
(function(){
    function foo(a,b){
        a = 20;
        console.log(a,b);  // 20 2
        console.log(arguments[0],arguments[1]); // 20 2
    }
    foo(1,2)
})(); 

// 嚴格模式
(function(){
 "use strict";
    // 形參 和 arguments 之間的區別;
    // 形參是變量能夠隨意賦值;
    // arguments 就是對應實參的關鍵字獲取全部的實參,進行使用,不會被改變;
    function foo(a,b){
        a = 20;
        console.log(a,b);  // 20, 2 
        console.log(arguments[0],arguments[1]);  // 1, 2 
    }
    foo(1,2)
})();
複製代碼

以上代碼中,函數 foo() 傳入兩個參數 a,b 。調用這個函數時傳入了兩個參數「1,2」,這個值賦個了對應的變量。而在函數內部,a 的值被修改成「20」。

在非嚴格模式下,這個修改的值也會改變 arguments[0] 的值; 但在嚴格模式下,arguments[0] 的值仍然是傳入的值。

四、arguments 的嚴格使用,部分功能禁用了

淘汰了 arguments.calleearguments.caller。 在非嚴格模式下,這兩個屬性一個是引用函數自己,一個是引用調用函數。而在嚴格模式下,這兩個屬性都被禁用了。

(function(){
    function foo(){
       // arguments.callee 指向了當前的函數自己;
       console.log(arguments.callee);
    }
    foo()
})();  // 結果: ƒ foo(){console.log(arguments.callee);}

(function(){
 "use strict";
    function foo(){
       // 禁用掉了大部分arguments的屬性;
       console.log(arguments.callee)
    }
    foo()
})();  // 報錯:TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments
複製代碼

相似的,嘗試讀寫函數的 caller 屬性也會拋出 TypeError(類型錯誤)。本身能夠嘗試一下呦!

五、嚴格模式之中對 this 的嚴格(抑制this

JavaScript 中一個最大的安全問題,也是最容易讓人迷惑的地方就是在某些狀況下如何抑制this的值。

在非嚴格模式下,nullundefined 值會被轉換爲全局對象 window。而在嚴格模式下,函數的 this 值始終是指定的值,不管指定的是什麼值。

(function(){
    function foo(){
        // this 指向 window;
       console.log(this);
    }
    foo()
})(); // 結果:Window 

(function(){
 "use strict";
    function foo(){
        // 禁用指向了 window 的 this,讓 this 指向 undefined
       console.log(this);
    }
    foo()
})();  // 結果:undefined
複製代碼

在之後的編程之中,this 最沒有用的指向就是全局對象 window

六、禁用 with(){} 語句

在非嚴格模式下的 with 語句可以改變解析標識符的路徑,但在嚴格模式下,with 被拋棄了。所以,在嚴格模式下使用 with 會致使語法錯誤。

(function(){    
    with(Math){
        // 能夠省略對象前置;
        console.log(random()); // => Math.random()
        console.log(PI);  // => Math.PI
    }
})();  

// 嚴格模式之下禁用 with(){}
(function(){
 "use strict";
    with(Math){
        console.log(random());
        console.log(PI);
    }
})();  // 報錯:Uncaught SyntaxError: Strict mode code may not include a with statement
複製代碼

在非嚴格模式下,with能夠改變做用域鏈,他可讓他裏面的代碼的做用域鏈的最頂端變成 with 括號裏面的這個對象。做用域鏈是通過很複雜的狀況生成的結構,做用域鏈改了以後,系統內核會消耗大量的效率去更改做用域鏈,是會把程序變得很是慢的。因此 ES5 的嚴格模式爲了提升效率,禁用 with 語句。

七、在嚴格模式之中被禁用的進制:不容許使用八進制

以 0 開頭的八進制字面量過去常常會致使不少錯誤,在嚴格模式下,八進制字面量已經成爲無效的語法了。

(function(){
    // 0 開頭就是八進制的標誌;
    console.log(012);
})(); // 結果: 10 (自動轉化成十進制)

(function(){
 "use strict"
    console.log(012)
})(); //報錯:Uncaught SyntaxError: Octal literals are not allowed in strict mode.
複製代碼
補充:ES5 也修改了嚴格模式下的 parseInt() 的行爲。現在八進制的字面量在嚴格模式下會被看成以 0 開頭的十進制字面量。例如:
(function(){
    var value = 012;
    console.log(value);
 })(); // 結果: 10 

 (function(){
 "use strict";
    var value = parseInt("012");
    console.log(value); 
 })(); // 結果: 12 
複製代碼

若是對您有幫助,歡迎點贊關注;文章若有遺漏之處歡迎評論區留言討論。

相關文章
相關標籤/搜索