返回文章列表

JavaScript Hoisting:變數與函式提升

10 分鐘
前端JavaScript

在 JavaScript 中,變數和函式的宣告會在程式碼執行前被處理,這個行為稱為 Hoisting (提升)。

理解 Hoisting,能幫助你預測程式碼的行為,避免意外的 undefinedReferenceError


什麼是 Hoisting

JavaScript 在執行程式碼之前,會先建立執行環境。在這個階段,JavaScript 會掃描所有的變數和函式宣告,並將它們「提升」到作用域的頂端。

這個過程就是 Hoisting。

Hoisting 不是真的把程式碼移動到上面,而是 JavaScript 引擎在執行前就先處理了這些宣告。


var 的 Hoisting

var 宣告的變數會被提升,並自動初始化為 undefined

JavaScript
console.log(name); // undefined
var name = "Charmy";

上面的程式碼,JavaScript 實際執行時等同於:

JavaScript
var name;
console.log(name); // undefined
name = "Charmy";

宣告被提升了,但賦值沒有,所以在賦值之前存取變數會得到 undefined,而不是報錯。


letconst 的 Hoisting

letconst 也會被 Hoisting,但不會自動初始化。

在宣告之前存取它們,會進入暫時死區 (Temporal Dead Zone,TDZ),直接拋出 ReferenceError

JavaScript
console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "Charmy";
JavaScript
console.log(count); // ReferenceError: Cannot access 'count' before initialization
const count = 0;

TDZ 從作用域開始,到宣告語句執行為止。這段期間內,變數存在但不能被存取。

TDZ 的設計讓錯誤更容易被發現,避免在宣告前意外使用變數。


函式宣告的 Hoisting

函式宣告 (Function Declaration) 會被完整提升,包含函式本體。

因此可以在宣告之前呼叫函式:

JavaScript
greet(); // "Hello"

function greet() {
  console.log("Hello");
}

這段程式碼可以正常執行,因為 JavaScript 在執行前就已經處理了整個函式宣告。


函式表達式的 Hoisting

函式表達式 (Function Expression) 的行為與變數一致,取決於使用 varlet 還是 const

使用 var

JavaScript
greet(); // TypeError: greet is not a function

var greet = function () {
  console.log("Hello");
};

var greet 被提升並初始化為 undefined,呼叫 undefined() 會拋出 TypeError

使用 letconst

JavaScript
greet(); // ReferenceError: Cannot access 'greet' before initialization

const greet = function () {
  console.log("Hello");
};

const greet 被提升但進入 TDZ,在宣告前存取會拋出 ReferenceError

箭頭函式

箭頭函式也是函式表達式,行為與上述相同:

JavaScript
greet(); // ReferenceError: Cannot access 'greet' before initialization

const greet = () => {
  console.log("Hello");
};

差異總覽

Hoisting初始化宣告前存取
varundefined回傳 undefined
let無 (進入 TDZ)ReferenceError
const無 (進入 TDZ)ReferenceError
函式宣告是 (完整提升)完整函式可以正常呼叫
函式表達式同變數規則同變數規則同變數規則

總結

  • var 被提升並初始化為 undefined,宣告前使用不報錯但可能產生難以察覺的 bug
  • letconst 被提升但進入 TDZ,宣告前使用會直接報錯,錯誤更容易被發現
  • 函式宣告會被完整提升,可以在宣告前呼叫
  • 函式表達式不會被完整提升,行為與變數一致

實務上,建議先宣告再使用,避免依賴 Hoisting 的行為,讓程式碼更清晰易讀。