JavaScript 課程 – 變數與資料型別
主題:嚴格模式('use strict')
簡介
在 JavaScript 的開發歷程中,嚴格模式(Strict Mode) 是一項重要的語法升級,它能讓程式在執行前即發現許多隱藏的錯誤與不安全的行為。對於剛踏入前端開發的初學者,以及想要提升程式碼品質的中級開發者而言,了解並善用嚴格模式是寫出可維護、可靠程式的第一步。
嚴格模式的核心目標是 「把不安全或不明確的語法變成錯誤」,從而迫使開發者以更嚴謹的方式撰寫程式。它不僅可以防止意外的全域變數、避免 this 被自動指向全域物件,還能阻止某些已被棄用的語法。透過本文的說明與範例,你將能快速掌握如何在不同情境下啟用嚴格模式,並了解它在實務專案中的最佳使用方式。
核心概念
1. 什麼是嚴格模式?
嚴格模式是一種 ECMAScript 5(ES5)之後引入的執行環境,透過在程式檔案或函式最前方加上字串 'use strict' 來啟用。啟用後,JavaScript 會在解析階段對以下行為拋出 SyntaxError 或 ReferenceError,而不是悄悄容忍或自行修正。
注意:嚴格模式是 可選 的,若未明確宣告,程式仍會在「非嚴格」模式下執行。
2. 啟用方式
| 範圍 | 語法範例 | 說明 |
|---|---|---|
| 全域 | javascript\n'use strict';\n// 之後的全部程式皆為嚴格模式\n |
直接在檔案最上方加入,整個檔案皆受限制。 |
| 函式 | javascript\nfunction foo(){\n 'use strict';\n // 只在 foo 內部生效\n}\n |
僅在該函式內部啟用,不影響外部程式。 |
| 模組 | ES6 模組(import/export)自動為嚴格模式。 |
不需要額外宣告,所有模組均為嚴格。 |
小技巧:在大型專案中,建議以 全域嚴格模式 為主,搭配 ES6 模組,可確保每個檔案都受到保護。
3. 嚴格模式的主要限制
| 限制項目 | 非嚴格行為 | 嚴格模式結果 | 為什麼要限制 |
|---|---|---|---|
| 隱式全域變數 | x = 10;(未宣告)會自動成為全域變數 |
ReferenceError: x is not defined |
防止意外污染全域命名空間 |
this 之預設值 |
在函式直接呼叫時 this === window(瀏覽器) |
this === undefined(在嚴格模式) |
避免在非物件方法中誤用 this |
| 重複的參數名稱 | function foo(a, a) {} 允許(舊版) |
SyntaxError |
明確參數意圖,防止混淆 |
eval 的作用域 |
eval 可在呼叫者作用域新增變數 |
eval 僅在自己的作用域內部運作 |
防止 eval 改寫外部變數 |
| 刪除不可刪除的屬性 | delete Object.prototype 失敗卻不拋錯 |
SyntaxError |
保護內建屬性不被破壞 |
| 八進位字面值 | var n = 010;(被解讀為八進位) |
SyntaxError |
消除語法歧義 |
with 陳述式 |
with (obj) {} 可改變作用域 |
SyntaxError |
with 會導致作用域難以追蹤 |
| 保留字 | implements, interface… 在舊版可作為變數名 |
SyntaxError |
為未來擴充保留關鍵字 |
程式碼範例
以下示範 5 個常見且實用的範例,說明嚴格模式對程式行為的影響與最佳寫法。
範例 1:防止隱式全域變數
// 非嚴格模式(會產生隱式全域變數)
function nonStrict() {
x = 100; // ← 沒有宣告的變數,會自動掛在全域
}
nonStrict();
console.log(x); // 100
// 嚴格模式(會拋出錯誤)
'use strict';
function strictMode() {
// y = 200; // ← 解除註解會得到 ReferenceError
let y = 200; // 正確寫法:使用 let/const/var 宣告
}
strictMode();
// console.log(y); // ReferenceError: y is not defined
重點:在嚴格模式下,所有變數必須先宣告(
let、const、var),才能使用。
範例 2:this 的預設值
function showThis() {
console.log(this);
}
// 非嚴格模式:直接呼叫時 this 會指向全域物件 (window)
showThis(); // [object Window]
// 嚴格模式:直接呼叫時 this 為 undefined
'use strict';
function showThisStrict() {
console.log(this);
}
showThisStrict(); // undefined
// 若以物件方法呼叫,兩者皆指向該物件
const obj = {
name: 'Alice',
greet: function() {
console.log(this.name);
}
};
obj.greet(); // Alice
技巧:在寫函式庫或類別時,使用嚴格模式可以避免
this被意外指向全域,減少 bug。
範例 3:禁止 with 與八進位字面值
'use strict';
// with (Math) { // SyntaxError: Strict mode code may not include a with statement
// console.log(sin(0)); // 會在非嚴格模式下正常執行
// }
let octal = 0o10; // 正確寫法:使用 0o 前綴
console.log(octal); // 8
// let oldOctal = 010; // SyntaxError: Octal literals are not allowed in strict mode
說明:
with會改變作用域解析,容易產生不可預期的行為;八進位字面值的舊寫法 (010) 已被棄用,使用0o前綴才是標準寫法。
範例 4:eval 的作用域限制
'use strict';
function testEval() {
eval('var a = 5;'); // a 只在 eval 本身的作用域內
// console.log(a); // ReferenceError: a is not defined
}
testEval();
為什麼重要:在非嚴格模式下,
eval可以在呼叫者作用域中新增變數,容易造成變數衝突與安全問題。嚴格模式將eval的作用域限制在自己的範圍,提升程式的可預測性。
範例 5:ES6 模組自動嚴格模式
// file: math.js(ES6 模組)
export function add(a, b) {
// 這裡自動為嚴格模式
return a + b;
}
// file: main.js
import { add } from './math.js';
console.log(add(3, 4)); // 7
結論:只要使用
import/export,即使沒有寫'use strict',模組內部也會自動套用嚴格模式,讓開發者更安心。
常見陷阱與最佳實踐
| 陷阱 | 可能的錯誤 | 解決方式 |
|---|---|---|
忘記在函式開頭加 'use strict' |
程式仍在非嚴格模式,隱式全域變數不易發現 | 統一在檔案最上方加入 'use strict',或使用 ES6 模組。 |
在非模組環境中混用 script 與 module |
同一檔案可能同時執行非嚴格與嚴格程式碼,導致行為不一致 | 將 type="module" 加到 <script> 標籤,確保整個檔案走嚴格模式。 |
使用 var 宣告變數,卻期望塊級作用域 |
var 仍會提升(hoisting),在嚴格模式下仍會產生意外 |
改用 let / const,確保變數僅在區塊內有效。 |
在嚴格模式下使用 arguments.callee |
arguments.callee 被禁止,拋出 TypeError |
若需要遞迴,直接使用函式名稱或 箭頭函式。 |
| 刪除不可刪除的屬性 | delete Object.prototype 會產生 SyntaxError |
避免刪除內建屬性,若真的需要,使用 Object.defineProperty 重新定義。 |
最佳實踐:
- 全域啟用嚴格模式:在每個 JavaScript 檔案的最上方放置
'use strict';,或直接使用 ES6 模組。 - 統一使用
let/const:減少變數提升與意外覆寫。 - 避免使用
eval:若必須使用,確保內容可信且在嚴格模式下執行。 - 使用 Linter(如 ESLint):設定
strict: ["error", "global"],讓編譯時即捕捉未啟用嚴格模式的檔案。 - 在測試環境驗證:加入單元測試,確保在嚴格模式下的程式碼行為與預期一致。
實際應用場景
1. 前端框架與函式庫開發
在開發像 React、Vue、Angular 這類大型框架時,所有模組皆以 ES6 import/export 方式編寫,自動套用嚴格模式。框架開發者會利用嚴格模式保證:
- 組件內部不會意外產生全域變數,避免不同組件之間的命名衝突。
this的行為可預測,特別在 class component 中,this必須指向實例。
2. Node.js 後端服務
Node.js 支援 ES6 模組(.mjs)或 CommonJS(require)。在 CommonJS 模組中,仍需手動加入 'use strict':
// file: db.js
'use strict';
const mysql = require('mysql2');
// 其餘程式碼...
此舉可防止在伺服器端意外創建全域變數,減少因變數污染導致的不可預期錯誤。
3. 舊版瀏覽器相容性
在需要支援 IE11 或更舊的環境時,仍可使用嚴格模式(IE9+ 已支援)。開發者可以在 Babel 轉譯過程中自動加入 'use strict',確保所有產出的 ES5 代碼皆受保護。
4. 安全性敏感的程式(如金流、認證)
在處理 金流、使用者認證 等安全性敏感的功能時,嚴格模式能降低因 eval、全域變數或 with 所導致的攻擊面。配合 CSP(Content Security Policy)一起使用,能大幅提升前端的安全防護。
總結
- 嚴格模式 是 JavaScript 中提升程式碼品質、減少錯誤與安全漏洞的關鍵工具。
- 只要在檔案最上方加上
'use strict';,或使用 ES6 模組,即可自動享有嚴格模式的保護。 - 與
let/const、模組化、ESLint 等現代開發實踐結合,能讓程式更易維護、錯誤更早被捕獲。 - 初學者在寫練習題或小型專案時,務必養成 「每個檔案都使用嚴格模式」 的好習慣;中級開發者則應在團隊規範、CI 流程中強制執行,確保整個代碼基礎都受保護。
透過本文的概念說明與實務範例,你現在已經能夠:
- 正確在全域或函式層級啟用嚴格模式。
- 立即辨識並修正因 隱式全域變數、
this預設值、with等產生的常見錯誤。 - 在前端框架、Node.js 後端或安全性敏感的應用情境中,安全且一致地使用嚴格模式。
把 嚴格模式 當作寫 JavaScript 的基本安全網,未來你會發現它不只是「防呆」工具,更是提升程式碼可讀性、可維護性與安全性的 必備武器。祝你寫程式順利,寫出乾淨、可靠的 JavaScript!