在 JavaScript 中,所謂的 IIFE 是 “Immediately Invoked Function Expression” 的縮寫,即「立即執行函數」,指的是當函數被定義後,就會立即執行;除了本身會被立刻執行的特性之外,通常會被用來創建一個私有作用域(private scope)以避免汙染全局作用域(global scope)。
基本語法
一般來說,有兩種方式可以創建立即執行函數,一種是使用 function
關鍵字進行宣告,另外一種則是使用箭頭函數(arrow function)表達式:
(function() {
console.log("this is an IIFE");
})();
(() => {
console.log("this is an IIFE");
})();
在上述的語法中,函數的定義被包裹在第一組括號中,可以使其被視作是表達式(expression),而第二組括號則表示要被立即執行。
以上兩種創建 IIFE 的方式並沒有太大的差異,需要注意的是涉及 this
變數的使用時,指向的物件會略有不同。
使用優點
- 避免汙染全局命名空間:在 IIFE 中的變數與函數,其作用域僅限於 IIFE 本身,可以減少全局變數與函數的數量,降低命名空間衝突的可能性﹒
- 封裝與私有性:在 IIFE 中的變數與函數,無法被外面的作用域所訪問與修改,據此可以保持變數與函數的私有性。
- 立即執行函數:由於 IIFE 在定義後就會立即執行,適合用於那些只需要被執行一次的函數,比如說作為初始化作用的函數。
使用範例
私有變數
(function() {
var privateMessage = "I am private";
console.log(privateMessage); // Outputs: "I am private"
})();
console.log(privateMessage);
上述這段程式範例中,當在 IIFE 之外訪問位於 IIFE 內的變數時,會拋出引用錯誤:Uncaught ReferenceError: privateMessage is not defined
。
封裝函數
const funcBox = (function () {
const privateMessage = "Hello from IIFE function!";
function showMessage() {
console.log(this.message); // this 依賴於調用上下文
}
return {
message: privateMessage,
reveal: showMessage
};
})();
// 此時 this 為 funcBox 物件
// 輸出 "Hello from IIFE function!"
funcBox.reveal();
在傳統函數中,變數 this
取決於函數調用時的上下文。在上述範例中,當 showMessage
被 funcBox.reveal
方法調用時,變數 this
會指向 funcBox
物件。
const funcBox = (function () {
const privateMessage = "Hello from IIFE function!";
const showMessage = () => {
console.log(this.message); // this 繼承自父上下文,這裡是全局或 undefined
};
return {
message: privateMessage,
reveal: showMessage
};
})();
// 此時 this 為 windows 物件或 undefined
// 輸出 undefined
funcBox.reveal();
箭頭函數中,變數 this
來自於函數定義時的上下文,而不是調用時的上下文。在上述的範例中,由於 showMessage
是在 IIFE 中定義的,因此 this
將指向全局物件(在瀏覽器中是 window
,但若開啟 strict mode
則是 undefined
);當 funcBox.reveal
方法調用時,變數 this
還是指向箭頭函數定義時的上下文。