JS-立即被呼叫的函式 (IIFE)

立即被呼叫的函式 (Immediately Invoked Function Expression, IIFE)

前言

在 2018 iT 邦幫忙鐵人賽,看到Kuro大的重新認識 JavaScript 系列文,仔細的閱讀後,紀錄自己觀念不足的部份,也非常推薦給大家觀看此系列文。


立即被呼叫的函式 (IIFE)

IIFE 的好處,就是可以減少「全域變數」的產生,同時也避免了變數名稱衝突的機會

如果你有去看過 jQuery 的原始碼,就會發現 jQuery 也用了相同的手法將 window 與 undefined 保留起來:

1
2
3
4
5
(function( window, undefined ) {

// 略...

})( window );

當迴圈遇到 function

題目:
假設想透過迴圈 + setTimeout 來做到,在五秒之內,每秒鐘依序透過console.log印出:0 1 2 3 4

1
2
3
4
5
6
7
8
// 假設想透過迴圈 + setTimeout 來做到
// 每秒鐘將 i 的值 console 出來

for( var i = 0; i < 5; i++ ) {
window.setTimeout(function() {
console.log(i);
}, 1000);
}

真的是這樣嗎? 我們來看看執行的結果。

執行的結果是, console.log() 會在「一秒鐘之後」同時印出「五次 5」。

1
2
3
4
5
5
5
5
5
5
「切分變數有效範圍的最小單位是 “function” 」
「切分變數有效範圍的最小單位是 “function” 」
「切分變數有效範圍的最小單位是 “function” 」

很重要,所以要再講三次。

所以我們利用 IIFE 稍微修改一下:

IIFE
1
2
3
4
5
6
7
8
9
10
for( var i = 0; i < 5; i++ ) {

(function(x){
// 將原本的 1000 改成 1000 * x
window.setTimeout(function() {
console.log(x);
}, 1000 * x);
})(i);

}

像這樣,就可以依序印出我們要的結果囉!


ES6-let、const

ES6 以後新增了 letconst,且改以 { } 作為它的 Scope。

換句話說,將範例中的 for 改為 let 就可以做到保留 i 在執行迴圈當下的「值」的效果:

1
2
3
4
5
for( let i = 0; i < 5; i++ ) {
window.setTimeout(function() {
console.log(i);
}, 1000);
}