JS專題之嚴格模式

ECMAScript 5 引入了 strict mode ,如今已經被大多瀏覽器實現(從IE10開始)javascript

1、什麼是嚴格模式

顧名思義,JavaScript 嚴格模式就是讓 JS 代碼以更嚴格的模式執行,不容許可能會引起錯誤的代碼執行。在正常模式下靜默失敗的代碼,嚴格模式下就會拋出錯誤。java

2、爲何要過渡到嚴格模式

  1. 嚴格模式下的代碼在運行的時候,更容易經過拋出的錯誤定位到問題所在的地方
  2. 嚴格模式可以幫助你編寫更符合規範的代碼
  3. 消除 JavaScript 語言上一些不合理,比較怪異的行爲
  4. 爲將來新版本的 JavaScript 作鋪墊
  5. 有時候,嚴格模式下的 JavaScript 代碼運行起來更快

3、如何使用

· 腳本文件範圍webpack

"use strict"; 放在腳本文件的第一行。整個腳本文件就會以「嚴格模式」執行。web

· 函數做用域範圍數組

"use strict"; 放在函數體的第一行,則整個函數以"嚴格模式"運行。瀏覽器

文件合併時,寫在腳本文件第一行的 "use strict"; 來實現嚴格模式會失效,能夠將腳本文件的代碼放在一個當即執行表達式中。安全

(funciton() {
    "use strict";
    ...
})()
複製代碼

4、嚴格模式的具體定義

  1. 嚴格模式下沒法再隱式建立全局變量 也就是,變量必須聲明後才能使用,正常模式直接賦值給一個未定義的變量時,會將變量定義爲全局變量。
"use strict";
var a = b = 3;  // Uncaught ReferenceError: b is not defined

以上代碼等於:
var a;
b = 3;
a = b;

複製代碼
  1. 禁止 this 關鍵字指向全局對象 正常模式下,函數中若是沒有指明 this 對象,JS 則會將 this 隱式指向爲全局對象。若是綁定的值是非對象,將被自動轉爲對象再綁定上去,而 null 和 undefined 這兩個沒法轉成對象的值,將被忽略。

嚴格模式下,必須指明 this 的指向對象。若是沒有指明的話,this的值爲 undefined閉包

var name = "foo";
function func() {
 "use strict";
    this.name;  // Uncaught TypeError: Cannot read property 'name' of undefined
}
func();  // 沒有加 new 關鍵字
new func();

function func() {
    return this
}

func() // window
func.call(8) // Number {8}
func.call(true) // Boolean {true}
func.call("abcd")  // {"abcd"}
func.call(null) // window
func.call(undefined) // window
 "use strict"
function func() {
    return this
}

func() // undefined
func.call(8) // 8
func.call(true) // true
func.call(null) //null
func.call(undefined) // undefined
複製代碼
  1. 不容許在函數內部遍歷調用棧 禁止使用 arguments.callee、arguments.caller、fn.caller、fn.callee; 在嚴格模式下,arguments.callee 是一個不可刪除屬性,並且賦值和讀取時都會拋出異常
function func() {
 "use strict";
	func.caller;  // 報錯
	func.arguments; // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
func()
複製代碼
  1. 禁止向對象的只讀屬性賦值,禁止刪除對象的不可設置屬性, 禁止向不可擴展的對象添加屬性 沒法刪除 var 聲明的變量。

在正常模式中,給對象的只讀屬性賦值, 刪除對象的不可設置屬性,添加不可擴展對象的新屬性,會靜默失敗。app

可是在嚴格模式中,會拋出錯誤。 另外,字符串的屬性 length 也是隻讀屬性,修改後會報錯。函數

"use strict";
var str = "abc"
str.length = 8  // Uncaught TypeError: Cannot assign to read only property 'length' of string 'abc'
 'use strict';
var obj = Object.defineProperty({}, 'a', {
  value: 37,
  writable: false
});
obj.a = 123; // Uncaught TypeError: Cannot assign to read only property 'a' of object '#
 'use strict';
var obj = Object.defineProperty({}, 'p', {
  value: 37,
  configurable: false
});
delete obj.p  // Uncaught TypeError: Cannot delete property 'p' of #<Object>

var obj = {};
Object.preventExtensions(obj);
obj.title = "hello";  // Uncaught TypeError: Cannot add property title, object is not extensible
複製代碼
  1. 對象不容許有重名的屬性,函數不容許有重名的參數 在正常模式中,對象的重名屬性,位置靠後會覆蓋位置靠前的重名屬性。函數也是,函數體查找到的參數,靠後的重名參數會覆蓋靠前的重名參數。
"use strict";
var o = { 
    p: 1,
    p: 2
   };
// IE報錯:strict 模式下不容許一個屬性有多個定義, 新版的 Chrome 和 firefox 並不會報錯,會採用覆蓋機制。
 "use strict";
function func(a, a) {
    console.log(a)
}
func(1, 2) // IE報錯: strict 模式下不容許正式參數名稱重複。新版的 Chrome 和 firefox 並不會報錯,會採用覆蓋機制。
複製代碼
  1. 靜態綁定 JavaScript 支持動態綁定,也就是 JavaScript 的屬性和方法是在運行時肯定,而不是在編譯時肯定。 因而,JavaScript 嚴格模式禁用了 with 語句, 由於使用了 with 語句,with 語句塊中變量沒法肯定是外部全局變量仍是傳入的對象屬性。
"use strict";
var x = 17;
with (obj) // !!! 語法錯誤
{
  // 若是沒有開啓嚴格模式,with 中的這個x會指向 with 上面的那個 x,仍是obj.x?
  // 若是不運行代碼,咱們沒法知道,所以,這種代碼讓引擎沒法進行優化,速度也就會變慢。
  x; // Uncaught SyntaxError: Strict mode code may not include a with statement
}
複製代碼

eval 關鍵字再也不會給上層函數(surrounding function)或者全局引入一個新的變量。在嚴格模式中,eval 語句會建立本身的一個做用域,eval 裏的變量只能在 eval 內部使用。

  1. arguments 的限定 嚴格模式規定名稱爲 eval 和 arguments 不能經過程序語法被綁定(be bound)或賦值 嚴格模式下,參數的值不會隨 arguments 對象的值的改變而變化。

正常模式中,對參數從新賦值,會修改 arguments 類數組對象下的參數值。同時,修改 arguments 類數組對象的值,也會修改函數參數的值。

嚴格模式下,不只參數的值不會隨着 arguments 類數組對象的變化而變化,參數的變化也不會引發 arguments 對象的變化,arguments 對象會記住參數的傳入初始值。

function func(a) {
"use strict"
  a = 8;
  // arguments[0] = 8
  return [a, arguments[0]]
}

func(3) // [8, 3]

function func(a) {
"use strict"
  arguments[0] = 8
  return [a, arguments[0]]
}

func(3) // [3, 8]
複製代碼
  1. ES5禁止在非函數代碼塊聲明函數 ES5 的嚴格模式只容許在全局做用域或函數做用域聲明函數。也就是說,不容許在非函數的代碼塊內聲明函數。
if (true) {
  function add() {
  }
}
add()

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

以上代碼在嚴格模式是禁止的,可是在 ES6 中,是容許在代碼塊中聲明函數的。
複製代碼
  1. 保留關鍵字 嚴格模式中一部分字符變成了保留的關鍵字。這些字符包括implements, interface, let, package, private, protected, public, staticyield。在嚴格模式下,你不能再用這些名字做爲變量名或者形參名
function private() {"use strict" }  //Uncaught SyntaxError: Unexpected strict mode reserved word
複製代碼
  1. 嚴格模式禁止八進制數字語法

5、向嚴格模式過渡

嚴格模式可以幫助咱們寫出更安全,更有規範的代碼,則應該避免一些危險的寫法,採用更好的寫法:

  1. 變量先聲明,再使用,
  2. this 應該在指向本身建立的對象時使用。
  3. arguments 應該在函數第一行就拷貝出來。

6、嚴格模式的缺點

  1. 如今的代碼都會進行文件壓縮和合並,此時嚴格模式就會失效。

總結

如今的 webpack 會在打包的時候默認是嚴格模式,因此如今不用再手動寫 use strict了。嚴格模式能幫助咱們以更規範的方式書寫代碼,可是不管是否嚴格模式,都應該注意代碼的規範,避免隱式 bug 的出現。

2018/02/08 @Starbucks

歡迎關注個人我的公衆號「謝南波」,專一分享原創文章。

掘金專欄 JavaScript 系列文章

  1. JavaScript之變量及做用域
  2. JavaScript之聲明提高
  3. JavaScript之執行上下文
  4. JavaScript之變量對象
  5. JavaScript之原型與原型鏈
  6. JavaScript之做用域鏈
  7. JavaScript之閉包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值傳遞
  11. JavaScript之例題中完全理解this
  12. JavaScript專題之模擬實現call和apply
  13. JavaScript專題之模擬實現bind
  14. JavaScript專題之模擬實現new
  15. JS專題之事件模型
  16. JS專題之事件循環
  17. JS專題之去抖函數
  18. JS專題之節流函數
  19. JS專題之函數柯里化
  20. JS專題之數組去重
  21. JS專題之深淺拷貝
  22. JS專題之數組展開
相關文章
相關標籤/搜索