好的,這是一個非常基礎且重要的概念。我們來詳細解析一下 JavaScript 中的嚴格模式(Strict Mode)和非嚴格模式(Sloppy Mode)。
可以把它想象成參加一場考試:
- 非嚴格模式:就像是開卷、不計時的隨堂測驗,規則很寬松,寫得不那么標準也能得分,老師會盡量“猜測”你的意圖。
- 嚴格模式:就像是正式的閉卷大考,有嚴格的規范,任何不符合規則的寫法都會被立刻標記為錯誤,不留任何情面。
1. 什么是嚴格模式?
嚴格模式 (Strict Mode) 是在 ECMAScript 5 (ES5) 中引入的一種選擇性加入(opt-in)的機制,它為 JavaScript 代碼選擇了一種更嚴格、更受限的語法和錯誤處理規則。
它的本質是讓 JavaScript 引擎以一種更“嚴謹”的方式來解析和執行你的代碼,從而提高代碼的健壯性和安全性。
非嚴格模式 (Sloppy Mode) 則是 JavaScript 默認的、向后兼容的、更“寬容”的模式。
2. 為什么需要嚴格模式?
JavaScript 最初被設計為一門非常寬容的語言,為了讓網頁在各種意外情況下都能勉強運行(而不是直接崩潰)。但這種寬容性也導致了一些問題:
- 靜默錯誤 (Silent Errors):一些本該是錯誤的操作,在非嚴格模式下不會報錯,只會靜默失敗,這使得調試變得異常困難。
- 不安全的行為: 某些語法可能存在安全隱患或導致意外的全局變量污染。
- 阻礙引擎優化: 一些“壞語法”讓 JavaScript 引擎難以對代碼進行性能優化。
- 為未來做準備: 禁止一些未來可能被用作新關鍵字的保留字。
嚴格模式的誕生就是為了解決這些歷史遺留問題。
3. 如何開啟嚴格模式?
開啟嚴格模式非常簡單,只需在代碼的特定位置添加一個字符串字面量:
"use strict";
根據你放置的位置,它的作用域也不同:
-
全局嚴格模式: 將
"use strict";
放在腳本文件的最頂部。// my-script.js "use strict";// 整個文件都將以嚴格模式運行 let x = 10; // ...
-
函數內嚴格模式: 將
"use strict";
放在函數體的最頂部。function myStrictFunction() {"use strict";// 只有這個函數內部是以嚴格模式運行的let y = 20;// ... }
一個非常重要的現代知識點:
在 ES6 模塊 (
import
/export
) 和class
的代碼塊中,嚴格模式是默認開啟的,你無需手動添加"use strict";
。這就是為什么在現代前端框架(如 React, Vue)的開發中,你很少看到這行代碼,因為你寫的代碼基本上都已經是運行在嚴格模式下的模塊了。
4. 嚴格模式與非嚴格模式的主要區別
下面是一些最直觀和重要的區別,通過代碼對比會非常清晰:
a. 禁止意外創建全局變量
這是最經典的區別。
- 非嚴格模式:
function createGlobal() {mistake = "I am a global variable!"; // 忘記寫 let/const/var } createGlobal(); console.log(window.mistake); // "I am a global variable!" (在瀏覽器中) // 變量泄漏到了全局作用域,這是一個非常危險的副作用。
- 嚴格模式:
結論:嚴格模式將一個常見的“靜默錯誤”變成了“拋出錯誤”,讓你能立刻發現問題。"use strict"; function createGlobal() {mistake = "This will cause an error"; } // createGlobal(); // 這一行會直接拋出 ReferenceError,程序會中斷
b. 禁止對只讀屬性或不可擴展對象進行修改
- 非嚴格模式:
const obj = {}; Object.defineProperty(obj, 'readOnly', { value: 10, writable: false });obj.readOnly = 20; // 嘗試修改只讀屬性 console.log(obj.readOnly); // 10 (修改靜默失敗,不會報錯)
- 嚴格模式:
結論: 嚴格模式同樣將靜默失敗的操作變成了明確的錯誤。"use strict"; const obj = {}; Object.defineProperty(obj, 'readOnly', { value: 10, writable: false });// obj.readOnly = 20; // 這一行會拋出 TypeError
c. this
的指向不同
我們在之前的練習中已經遇到過。
- 非嚴格模式:
function showThis() {console.log(this); } showThis(); // 在瀏覽器中,會輸出全局的 window 對象
- 嚴格模式:
結論: 嚴格模式下的"use strict"; function showThis() {console.log(this); } showThis(); // 輸出 undefined
this
行為更安全,避免了意外地污染全局對象。
d. 禁止重復的參數名
- 非嚴格模式:
function sum(a, a, b) { // 不會報錯return a + a + b; // 實際上是第二個 a 生效 } console.log(sum(1, 2, 3)); // 2 + 2 + 3 = 7
- 嚴格模式:
結論: 嚴格模式在語法層面就杜絕了這種不合理的代碼。"use strict"; // function sum(a, a, b) { // 這一行在代碼解析階段就會拋出 SyntaxError // return a + b; // }
總結與建議
特性 | 非嚴格模式 (Sloppy Mode) | 嚴格模式 (Strict Mode) |
---|---|---|
意外全局變量 | 允許,靜默創建 | 禁止,拋出 ReferenceError |
修改只讀屬性 | 靜默失敗 | 禁止,拋出 TypeError |
全局函數this | 指向全局對象 (window ) | undefined |
重復參數名 | 允許(最后一個生效) | 禁止,拋出 SyntaxError |
最終建議:始終使用嚴格模式!
在今天,你沒有任何理由不使用嚴格模式。它能幫你寫出更健壯、更安全、更規范的代碼,并且能讓你避免很多難以調試的“幽靈bug”。
鑒于現代 JavaScript 的模塊和類已經默認開啟了嚴格模式,將 "use strict";
放在所有非模塊化的老腳本的頂部,應該成為你的一個標準習慣。