Q. IIFE
IIFE for Immediately Invoked Function Expression. 利用函式運算式, 建立一個匿名函式,接著立刻執行它.
優點是在它裡面的任何東西都在自己的範圍(closure), 而且因為它是函式, 有回傳值可把某些東西丟出範圍.目的就是減少全域變數的使用, 造成污染
IIFE另一個最重要的用途, 就是在新範圍內建立新的變數, 讓非同步程式碼可以正確地執行
// Anonymous function
function(){
// my special code
}(); // The parentheses make sure the anonymous function gets called immediately
寫法一:
(function(){
// my special code
}());
括號()代表的就是立刻執行該函式. 在語法上,括號()也可以被放到左括號)外面, 像寫法二
寫法二:
(function() {
// 這是 IIFE 本文
})();
傳入參數
(function(a, b) {
// a == 'hello'
// b == 'world'
})('hello', 'world');
IIFEs are also useful for establishing private methods for accessible functions while still exposing some properties for later use
這樣的做法好像建立一個 Instance, 有private attributes 及 public methods
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
})();
// 'counter' is an object with properties, which in this case happen to be
// methods.
counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5
Q. IIFE與非同步程式
原始問題如下
var i
for(i=5; i>0; i--) {
setTimeout(function () {
console.log(i===0 ? "go!" : i);
}, (5-i)*1000);
}
// 出現 go! go! go! go! go!
// 因為被傳入setTimeout的函式沒有被馬上呼叫, 一段時間後被呼叫時, reference 到的 i 值都是 0
// 使用ES6的 let 可以實質解決問題
解法1, 使用named function 來建立一個新範圍, 變數i在closure裡面, 所以可以keep local i 值
// 使用named function 來建立一個新範圍, 變數i在closure裡面, 所以可以keep local i 值
function loopBody(i) {
setTimeout(function() {
console.log(i===0 ? "go!" : i);
}, (5-i)*1000);
}
var i;
for(i=5; i>0; i--) {
loopBody(i);
}
// 所以是建立了6個不同的範圍, 與6個獨立的變數(外部範圍一個, 每次呼叫loopBody時一個)
解法2, 使用 匿名函式 IIFE 的寫法, 不用額外寫一個named function
var i;
for(i=5; i>0; i--) {
(function (i) {
setTimeout(function() {
console.log(i===0 ? "go!" : i);
}, (5-i)*1000);
})(i);
}
解法三, 在for loop中使用 let, 區塊範圍變數, 可以簡化問題, 不用額外做一個函式來建立新範圍, 作法如下
// 用 let 取代 var, let 可以使javascript在執行時, 每次迴圈都有一個新的獨立的i
for(let i=5; i>0; i--) {
setTimeout(function () {
console.log(i===0 ? "go!" : i);
}, (5-i)*1000);
}