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);
}

results matching ""

    No results matching ""