在 JavaScript 中,匿名函數是指沒有具名標識符的函數表達式。它們常被用作回調、立即執行函數表達式(IIFE)或構建閉包。本文將系統梳理匿名函數的定義、與閉包的區別、預編譯行為差異,以及三種常見的調用模式。
字面上理解,匿名函數就是「沒有名字的函數」。在代碼中,我們通過 function() { ... } 形式定義,並通常賦值給變量或作為參數傳遞。注意括號必須是英文半角狀態。
與閉包函數相比,匿名函數最大的優勢在於不污染全局對象。一旦執行完畢,其內部變量隨即變為不可達,垃圾回收器(GC)會自動回收記憶體。這與閉包形成鮮明對比:
function f1() {
var n = 999;
nAdd = function() { n += 1; }; // 全局變量,且是一個閉包
function f2() { alert(n); }
return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000 證明 n 長駐記憶體
上例中,f2 作為閉包被返回並賦值給全局變量 result,導致父函數 f1 的作用域鏈無法釋放,變量 n 長期佔用記憶體。而匿名函數若不被引用,執行後即刻回收。
普通函數聲明會在預編譯階段被提升(hoisting),而匿名函數作為函數表達式賦值給變量,變量聲明提升但賦值不提升:
function fuc() {
fuc1(); // 正常:函數聲明已提升
fuc2(); // 報錯:fuc2 為 undefined(變量提升了,但賦值未執行)
function fuc1() { alert("foo"); }
var fuc2 = function() { alert("bar"); };
}
先聲明函數對象,再通過尾部 () 立即執行:
(function() { /* code */ })();
利用括號強制解析器將 function 關鍵字視為表達式而非聲明,隨後立即調用:
(function() { /* code */ }());
使用 void 強制表達式返回 undefined,同時執行函數:
void function() { /* code */ }();
這三種模式本質相同,皆用於創建獨立作用域,避免變量洩漏到全局。實際開發中,IIFE 是構建模塊化代碼、實現私有變量的基石。