立即執行函數:IIFE (Immediately Invoked Function Expression)

在 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 取決於函數調用時的上下文。在上述範例中,當 showMessagefuncBox.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 還是指向箭頭函數定義時的上下文。