在常運用閉包是在處理回呼或計時器的時候,需要在某個不確定的時間點、以非同步方式呼叫某函式。
若沒有閉包機制,想要在同一時間執行多個動作,不論是事件處理、動畫、Ajax請求,將會非常困難;閉包不只是把建立時的值拍照紀錄而已,而是在狀態封裝後仍繼續活著,只要閉包存在,就可以修改裡頭的狀態。
function buildFunctions(){
    var arr = [];
    //for迴圈
    for (var i=0 ; i<3 ; i++){
        arr.push( //在arr陣列裡放入3個function
            function(){ 
                console.log(i);
            });//console.log不會在這時被執行,只是創造物件,因為還沒被呼叫
    }
    return arr;
}
var fs = buildFunctions();
fs[0]();
fs[1]();
fs[2]();
執行結果
for迴圈執行第一次時i為1,第二次i為2,第三次i為3
原因:
因為i++最先執行,最後i為2時,i++又執行了一次i為3,然後判斷i<3的表示式,發現i不小於3時才離開了迴圈,這時i離開的值是3,所以記憶體中i停留的值為3,而不是我們創造函數時候的值,所以三個輸出都一樣是3,因為三個都指向同一個記憶體位置。
console.log不是在它所在的地方執行,而是當我們呼叫函數時執行,i的值是在執行函數時後的值(還沒呼叫)
方法一:
使用ES6的let
function buildFunctions22(){ 
    var arr = [];
    //for迴圈
    for (var i=0 ; i<3 ; i++){
        let j = i; //用let宣告,每次for迴圈執行時,這會是記憶體中一個新的變數,會放在不同的記憶體位置。
        arr.push( 
            function(){ 
                console.log(j); 
            });
    }
    return arr;
}
var fs2 = buildFunctions2(); 
fs2[0](); 
fs2[1](); 
fs2[2]();
方法二:
IIFE立刻執行函數
獲得執行環境唯一的方法就是執行函數
function buildFunctions22(){ 
    var arr = [];
    //for迴圈
    for (var i=0 ; i<3 ; i++){
        arr.push( 
            (function(j){
                return function(){
                    console,log(j);
                }
            }(i))
        )
    }
    return arr;
}
var fs2 = buildFunctions2(); 
fs2[0](); 
fs2[1](); 
fs2[2]();
每執行新的一行,每次執行都創造了自己的執行環境,j會被存在這三個執行環境。
j它不需要到迴圈去找,只要到自己的這個執行環境就好,j的值會在迴圈執行時儲存。