JS中for循環裏面的閉包問題的緣由及解決辦法

JS中for循環裏面的閉包問題的緣由及解決辦法

感謝大神~!不是原博...數組

咱們先看一個正常的for循環,普通函數裏面有一個for循環,for循環結束後最終返回結果數組

function box(){
    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = i;        
    }
    return arr;
}
alert(box())                                    //正常狀況不須要閉包,就能夠達到預期效果,輸出結果爲一個數組0,1,2,3,4
 

有時咱們須要在for循環裏面添加一個匿名函數來實現更多功能,看下面代碼閉包

function box(){
    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = function(){
            return i;                            //因爲這個閉包的關係,他是循環完畢以後才返回,最終結果是4++是5
        }                                        //這個匿名函數裏面根本沒有i這個變量,因此匿名函數會從父級函數中去找i,
    }                                            //當找到這個i的時候,for循環已經循環完畢了,因此最終會返回5
    return arr;
}
//alert(box());                                    //執行5次匿名函數自己
//alert(box()[1]);                   //執行第2個匿名函數自己
//alert(box().length);                            //最終返回的是一個數組,數組的長度爲5
alert(box()[0]());                                //數組中的第一個數返回的是5,這是爲何?
 

上面這段代碼就造成了一個閉包:函數

閉包是指有權訪問另外一個函數做用域中的變量的函數,建立閉包的常見的方式,就是在一個函數內部建立另外一個函數,經過另外一個函數訪問這個函數的局部變量。post

在for循環裏面的匿名函數執行 return i 語句的時候,因爲匿名函數裏面沒有i這個變量,因此這個i他要從父級函數中尋找i,而父級函數中的i在for循環中,當找到這個i的時候,是for循環完畢的i,也就是5,因此這個box獲得的是一個數組[5,5,5,5,5]。spa

解決方案1code

在看解決方案一以前,咱們先看一下匿名函數的自我執行:blog

匿名函數自我執行的寫法是,在函數體外面加一對圓括號,造成一個表達式,在圓括號後面再加一個圓括號,裏面可傳入參數。ip

例以下代碼:作用域

(function(){
    alert('lee');                        //匿名函數自我執行(匿名函數)()
})();

咱們再來看解決方案1:it

 
function box(){
    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = (function(num){                    //自我執行,並傳參(將匿名函數造成一個表達式)(傳遞一個參數)
            return num;                            //這裏的num寫什麼均可以                    
        })(i);                                    //這時候這個括號裏面的i和上面arr[i]的值是同樣的都是取自for循環裏面的i                            
    }                                            
    return arr;
}
//alert(box());                                
//alert(box()[1]);
//alert(box().length);                            
alert(box()[0]);        
 

經過給匿名函數傳參,而傳遞的這個參數i是每次執行for循環裏面的i,每次傳遞的參數i的值都不同,匿名函數裏面的num接收傳遞的參數i,因此box()最終輸出結果爲[0,1,2,3,4]

解決方案2

這種方案的原理就是在匿名函數1裏面再寫入一個匿名函數2,這個匿名函數2須要的num值會在他的父級函數匿名函數1裏面去尋找,而匿名函數1裏面的num值就是傳入的這個參數i,和上面例子中的i是同樣的,

function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(num){
//num在這裏 //原理和上面一種方法同樣的,因此能夠實現閉包
return function(){ //在這個閉包裏面再寫一個匿名函數
return num;
};
})(i)
}
return arr;
}
//alert(box());
//alert(box()[1]);
//alert(box().length);
var b = box();
alert(b[0]());

box()最終返回結果[0,1,2,3,4],

解決方案3

若是將一個匿名函數自我執行的時候賦值給一個變量,那麼這個匿名函數中的圓括號的能夠去掉的,看下面代碼,

var tip = function(){                                //這樣把匿名函數自我執行的時候賦值給一個變量,那麼圓括號是能夠去掉的
    alert('lee');
}();

利用匿名函數的這一特色,咱們能夠將解決方案1中的代碼改進一下:

    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = function(num){                
            return num;                            
        }(i);                                
    }                                            
    return arr;
}
//alert(box());                                
//alert(box()[1]);
//alert(box().length);                            
alert(box()[4]);
相關文章
相關標籤/搜索