JavaScript 建立函數有兩種主要語法:**函數聲明**與**函數表達式**。兩者雖能產出相同功能,但因 **Hoisting(變量提升)** 機制導致行為差異巨大。本文深入剖析提升規則、執行順序、自調用函數表達式(IIFE)與現代最佳實踐,助你避開常見坑洞。
// 函數聲明
function foo() {}
// 函數表達式(匿名函數賦值給變數)
var bar = function() {};
// 具名函數表達式(利於堆疊追蹤除錯)
var baz = function bazName() {};
// 立即調用函數表達式 (IIFE) - 建立獨立作用域
(function() { var local = 1; })();
JavaScript 引擎在執行前會將 **聲明** 提升至作用域頂部:
undefined)。ReferenceError。console.log(foo); // [Function: foo] - 函數聲明完整提升
console.log(bar); // undefined - var 提升但未初始化
function foo() {}
var bar = function barName() {};
console.log(foo); // [Function: foo]
console.log(bar); // [Function: barName]
引擎實際執行等效順序:
foo、bar,賦值 undefined。foo,賦值給 foo。console.log(foo) → 印出函數。console.log(bar) → 印出 undefined。barName,賦值給 bar。console.log。| 特性 | 函數聲明 | 函數表達式 |
|---|---|---|
| 提升行為 | 完整提升(可先呼叫後聲明) | 僅變數提升(先呼叫會是 undefined/TypeError) |
| 嚴格模式區塊作用域 | ES2015+ 區塊級作用域 | 天然區塊級作用域(配合 const/let) |
| 除錯堆疊顯示 | 顯示函數名 | 匿名函數顯示 anonymous,具名表達式顯示具名 |
| 條件式定義 | 非標準、各引擎行為不一 | 標準、可靠 |
const + 箭頭函數 / 函數表達式:const add = (a, b) => a + b;
const factorial = function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); }; // 遞歸需具名
const。import/export)天然隔離作用域,無需 IIFE。this 上下文。var fn = new Function('a', 'b', 'return a + b;'); // 字串解析、效能差、無閉包、安全風險
掌握 Hoisting 與兩種函數定義的語義差異,是寫出可預測、可維護 JavaScript 程式碼的基石。