2

一段时间以来,我一直不确定围绕闭包的 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;
    }
});

但是......我总是对这条规则感到困惑。任何帮助消除这种混乱将不胜感激!

4

2 回答 2

3

不,即使您的第二个示例也不足以导致泄漏。badIdea附加到各个节点,$.each块将退出并被垃圾收集。所有现代浏览器都使用“标记和清除”算法进行 javascript 垃圾收集,该算法遵循父子关联并收集任何“无法访问”,即这些树之一无法访问的任何内容。

于 2012-05-22T17:07:11.280 回答
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; };
    }();

你不能再访问它,它是垃圾收集的候选者。

于 2012-05-22T17:20:05.800 回答