2012-05-22 70 views
2

我一直不確定關於閉包JS JS垃圾收集的規則一段時間,所以我想我可能會問...這是一個很好的例子,我很好奇涉及jQuery的$.each方法:關閉垃圾收集的混亂

storeSelection: function() { 
    var enabledIds = {}; 

    $.each(this.nodes, function(index, node) { 
     if (node.enabled) { 
      enabledIds[ node.id ] = true; 
     } 
    }); 

    this.selection = enabledIds; 
} 

上面的這段是,當然,對象文本的一部分。所以,我在外層函數的頂部創建了一個新對象,它將存儲數組中已啓用項的ID。使用jQuery的.each()方法,我循環訪問項目數組並記錄啓用ID。最後,我將選擇存儲爲父對象的成員。

我的問題涉及內部函數,它引用外部作用域中的enabledIds對象。由於enabledIds會滯留,是否阻止內部功能被收集?我會假設沒有,因爲它只是一個在內部函數結束時被清除的變量,對吧?要成爲一個漏洞,我認爲內在功能都需要進行硬參考外部對象,如:

$.each(this.nodes, function(index, node) { 
    this.badIdea = enabledIds; 
    if (node.enabled) { 
     enabledIds[ node.id ] = true; 
    } 
}); 

但是...我一直在這條規則有霧。任何幫助消除這種混亂將不勝感激!

回答

3

不,即使你的第二個例子不足以導致泄漏。 badIdea附加到各個節點,並且$.each塊將退出並被垃圾收集。所有現代瀏覽器對JavaScript垃圾收集使用「標記和掃描」算法,該算法遵循父與子的關聯,並收集任何「不可訪問」(即任何不能被這些樹中的一個訪問的任何內容)。

1

你是對的,來自內部函數(index,node)的變量將被垃圾收集,因爲它們不能再被訪問。

在這個例子中,你能訪問bigstr嗎?

a = function() { 
     var bigstr = new Array(1000000).join('x'); 
     return function() { return bigstr; }; 
    }(); 

是的,您可以:a(),所以它不是收集。這個例子如何:

a = function() { 
     var bigstr = new Array(1000000).join('x'); 
     return function(n) { return eval(n); }; 
    }(); 

再次,你可以:a('bigstr')

但是這一個:

a = function() { 
     var smallstr = 'x'; 
     var bigstr = new Array(1000000).join('x'); 
     return function(n) { return smallstr; }; 
    }(); 

您不能訪問它,和它的垃圾收集的候選者。