这个作用域/闭包在JavaScript中何时被垃圾回收?

3

我正在学习一门课程,涉及到作用域/闭包并简要提到垃圾回收。在课程中有一个问题被提出:

作用域存在多长时间?答案是——直到不再有任何引用它的变量。没错,我们基本上说了,闭包就像是对一个隐藏作用域对象的引用。只要还有某些函数仍然具有对该作用域的闭包引用,该作用域就会一直存在。但是,一旦闭包消失,作用域可能被垃圾回收。

var sum = function sumHndlr(x, y) {
    if (y !== undefined) {
        return x + y;
    } else {
        return function(y) {
            return x + y;
        }
    }
}

在我看来,闭包的引用是当我们将函数分配给sum变量时,但这是否意味着它会永久存在,或者我没有理解js在编译器解析等方面的执行方式?


“永远”是什么意思?是的,闭包将持续与“sum”一样长的时间,但那并不是“永远”... - Djizeus
也许我需要更多关于垃圾回收实际发生的澄清。因为目前我认为垃圾回收就像移除事件监听器一样。也许您可以解释一下为什么它不是永久的。谢谢! - Antonio Pavicevac-Ortiz
2
sum/sumHndlr不是闭包。你必须调用它(不带y)才能得到一个。然后,只要你将其保留在某个地方,它就会一直存在(以及它所关闭的x)。如果您想让我们提供更多信息,请向我们展示该调用。 - Bergi
没错——我认为那是正确的。内部函数是记住它的词法作用域的函数。我想我还没有明白它怎么会消失?对我来说,如果你将sum赋值为null或其他什么东西,那么它就会发生。但现在我只是猜测。 - Antonio Pavicevac-Ortiz
1
@AntonioOrtiz:函数对作用域的引用永远不会消失。只有当所有指向它的函数都被垃圾回收时,该作用域才能被垃圾回收。如果您执行了var add2 = sum(2);,那么将add2 = null赋值将使该函数有资格进行垃圾回收。 - Bergi
1个回答

2
简而言之,垃圾回收是Javascript解释器/虚拟机的后台进程,可以自动释放程序不再需要的对象的内存。
举个例子,当你从某个事件分发器中删除一个事件侦听器时(通常是一个函数),其他部分的程序可能没有引用该事件侦听器。因此,在某个未知的时间,垃圾回收器可以并将释放由事件侦听器占用的内存。
由于闭包引用了作用域对象,为了进行垃圾回收,它不仅需要被取消引用,而且还需要其所在的作用域也被取消引用。
如果我稍微修改一下你的示例:
/* some stuff ... */
function add10(a) {
  var adder = function (x) {
     return function(y) {
       return x + y;
     }
  }

  var sum = adder(10); //creates a closure
  return sum(a);
}

var thirty = add10(20);

/* Some more stuff ... */

调用add10函数后,尽管程序继续执行其他操作,但垃圾回收器可以释放与闭包sum相关联的内存,因为它不再被引用,也不再与其关联的作用域。

相比之下,在这个例子中:

/* some stuff ... */
function add10AndGet20Adder(a) {
  var adders = function (x, y) {
     return [function(z) {
       return x + z;
     }, function(z) {
       return y + z;
     }]
  }

  var sums = adders(10, 20); //creates a closure
  return [sums[0](a), sums[1]];
}

var result = add10AndGet20Adder(50);
var sixty = result[0];
var add20 = result[1];

/* Some more stuff ... */

当执行一些更多的操作时,sums[0]不再被引用,但是add20sums[1])仍然有一个引用到引用xy的作用域,因此sums中的两个闭包都不能被垃圾收集器释放,直到程序引用add20
我希望这样可以更清楚,尽管这些示例当然与实际代码相去甚远。在实践中,只有在开发长期运行的程序(例如单页应用程序或nodeJS服务器)并且使用闭包非常复杂时才需要担心这个问题。否则,闭包的内存使用量不太可能成为问题。
这个SO问题提供了关于JavaScript垃圾回收的更多细节:What is JavaScript garbage collection?

谢谢你用那种独特的函数形式(第二个)进行了详细的解释 - 或许对我来说是独特的,因为我从未见过;) 我也会去查看JS垃圾回收链接!干杯! - Antonio Pavicevac-Ortiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接