JavaScript 立即呼叫函式表達式 (IIFE)

在學習 Vue 的途中,偶然遇見了關於立即函式 (IIFE) 的關卡,在成功破關之際,就順便紀錄一下吧!

var 與 let 的觀念複習

有無 Hoisting(宣告前就使用):

  • 使用 var 宣告,結果會是 undefined:記憶體有準備位置 (Hoisting)
  • 使用 let 宣告,結果會是 not defined:還沒有準備空間

作用域 (Scope):

  • var 的作用域是 Function Scope(在整個函式的大括號內)
  • let 的作用域是 Block Scope(在任何的大括號內)

問題說明

我們學習 let 時可能遇過以下問題,這個問題是要讓 setTimeouti 能夠正確執行。

在學習 ES6 的 let 之後,我們知道這邊必須使用 let 而非使用 var 來宣告變數。

1
2
3
4
5
6
for (let i = 0; i < 10; i++) {
console.log(i);
setTimeout(function () {
console.log('這執行第' + i + '次');
}, 10);
}

但是,如果我們不使用 let,堅持要使用 var 的話,上述問題還有其他答案嗎?

立即函式 (IIFE)

沒錯!我們還可以使用 JavaScript 的立即函式。

顧名思義,”立即函式” 就是一種可以立即執行的函式,寫法如下:

1
2
3
(function () {
// Code
})();

我們可以發現整個 function 被一個括號 () 包住後,右邊又多出一個括號 ()

右邊這個最後的括號 ()就是代表立刻呼叫、執行該函式。

因此,我們立馬使用 “立即函式” 來改寫看看吧!

錯誤寫法

1
2
3
4
5
6
7
8
9
for (var i = 0; i < 10; i++) {
console.log(i);
setTimeout(
(function () {
console.log('這執行第' + i + '次');
})(),
1000
);
}

上述程式碼中,我們把 setTimeout 改寫成 “立即函式”,但這是錯誤答案!

雖然結果出來了,的確能夠立即執行,但是我們想要的延遲效果卻沒有了。

因此,我們應該額外寫一個 “立即函式”,再把 setTimeout 放在裡面,那樣才是正確解答。

正確寫法

1
2
3
4
5
6
7
8
9
10
for (var i = 1; i <= 10; i++) {
console.log(i);
// 為了凸顯差異,我們將傳入後的參數改名為 x
// 當然由於 scope 的不同,要繼續在內部沿用 i 也是可以的
(function (x) {
setTimeout(function () {
console.log('這是第' + x + '次執行');
}, 1000);
})(i); // 呼叫執行函式,並傳值 i,也就是將迴圈的 i 傳給 function()
}

這裡為了凸顯差異,我們將傳入後的參數改名為 x
當然,由於 Scope 不同的緣故,若要繼續在內部沿用 i 也是可以的。

所以,當我們每跑一次 for 迴圈,立即函式就會馬上呼叫執行一次,
並把 for 迴圈當下的 i 值傳給 function(){...},完成裡面 setTimeout 的動作。

Function 接收的值,不需要跟傳來的值同一名稱,這應該沒問題啦齁!

這樣就是正確的 “立即函式” 的使用姿勢啦!

參考資料

更多關於 “立即函式” 的資料,可參考以下網站:

  1. 立即函式(IIFE)

以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫。