讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議62:在循環體和異步回調中慎重使用閉包 >

建議62:在循環體和異步回調中慎重使用閉包

閉包在開發中具有重要的應用價值,由於閉包具有持久性,生成的閉包不會立即被銷毀,因此它會持續佔用系統資源。如果大量使用閉包,將會造成系統資源緊張,甚至導致內存溢出等錯誤。另外,閉包在回調函數中會帶來負面影響,因此在使用時應該慎重。

下面的示例利用閉包來存儲變量所有變化的值。


function f(x){

var a=;

for(var i=0;i<x.length;i++){

var temp=x[i];

a.push(function{

alert(temp+''+x[i])

});

}

return a;

}

function e{

var a=f(["a","b","c"]);

for(var i=0;i<a.length;i++){

a[i];

}

}

e;//調用函數e


在這個示例中,函數f的功能是:把數組類型的參數中每個元素的值分別封裝在閉包結構中,然後把閉包存儲在一個數組中,並返回這個數組。但是,在函數e中調用函數f,並向其傳遞一個數組(["a","b","c"]),然後遍歷函數f返回數組,此時會發現,數組中每個元素的值都是「c undefined」。

原來閉包中的變量temp並不是固定的,它會隨時根據函數運行環境中的變量temp的值變化而更新,這樣會導致臨時數組元素的值都是字符「c」,而不是「a」、「b」、「c」,同時,由於循環變量i遞增之後,最後的值是3,x[3]超出了數組的長度,所以結果就是undefined。

解決閉包存在缺陷問題的方法是:為閉包再包裹一層函數,然後運行該函數,並把外界動態值傳遞給它,這個函數接收這些值後傳遞給內部的閉包涵數,從而阻斷了閉包與最外層函數的實時聯繫。


function f(x){

var a=;

for(var i=0;i<x.length;i++){

var temp=x[i];

a.push(

(function(temp,i){

return function{

alert(temp+''+x[i])

}

})(temp,i)

);

}

return a;

}

function e{

var a=f(["a","b","c"]);

for(var i=0;i<a.length;i++){

a[i];

}

}

e;


同一個閉包通過分別引用能夠在當前環境中生成多個閉包。例如:


function f(x){

var temp=x;

return function(x){

temp+=x;

alert(temp);

}

}

var a=f(50)

var b=f(100)

a(5)//55

b(10)//110