关于闭包中垃圾收集的混淆

confusion about garbage collection among closures

本文关键字:于闭包 闭包      更新时间:2023-09-26

我一直不确定 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;
    }
});

然而。。。我总是对这个规则感到困惑。任何帮助澄清这种困惑将不胜感激!

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

你是

对的,来自内部函数(indexnode)的变量将被垃圾回收,因为它们不能再被访问了。

在此示例中,是否可以访问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; };
    }();

您无法再访问它,它是垃圾回收的候选对象。