現象對比
// 1. 全局直接寫
if (thisVariable) { } // ReferenceError: thisVariable is not defined
// 2. 函數內寫
function test() {
if (thisVariable) { } // 不報錯,thisVariable 被預編譯提升為 undefined
var thisVariable = {};
}
test();
原理:預編譯(Hoisting)
- **全局代碼**:逐行執行,遇到未聲明標識符直接拋 `ReferenceError`。
- **函數代碼**:執行前**預編譯階段**,掃描 `var`/`function` 聲明,創建變量對象,**賦值 `undefined`**。故函數內 `thisVariable` 實際為 `undefined`,`if` 判斷為 `false`,不報錯。
等價轉換
function test() {
var thisVariable = undefined; // 預編譯提升
if (thisVariable) { } // false,不執行
thisVariable = {}; // 真正賦值
if (thisVariable["thatProperty"]) { } // undefined,false
}
最佳實踐
- **嚴格模式** `"use strict";` 可部分捕獲未聲明賦值,但無法改變預編譯行為。
- **ES6 `let`/`const`**:**暫時性死區 (TDZ)**,塊級作用域內聲明前訪問直接報錯,**消除預編譯困擾**。
- 習慣**先聲明後使用**,避免依賴 `undefined` 隱式轉換邏輯。