JavaScript闭包问题:为什么第二次调用outerFn会创建一个新的outerVar实例?

JavaScript Closure question: why is the second call to outerFn creating a new instance of outerVar?

本文关键字:一个 实例 outerVar 创建 问题 闭包 为什么 第二次 outerFn 调用 JavaScript      更新时间:2023-09-26

我在理解闭包方面取得了进展,但我不明白下面的例子是如何创建闭包的。我将引用《学习jQuery》第392页中的一段话,以及作者对这个例子的看法。

作者说,因为"readyVar在函数调用之间持续存在",我们可以看到其中涉及到闭包。但是,对我来说,readyVar在调用innerFn之间持续存在只是因为匿名函数尚未完成执行。一旦匿名函数完成,就不会有对readyVar的引用,并且它将被垃圾收集。那么结束在哪里呢?在我的印象中,闭包涉及变量在定义变量的作用域之外的作用域中可引用。但是我在这里没有看到。

作者是说任何时候内部函数引用外部函数中定义的值,就会创建闭包吗?他不会是这个意思吧?

这条信息的其余部分引用了前面提到的那本书

$(document).ready(function() {
  var readyVar = 0;
  function innerFn() {
    readyVar++;
    $('#example-9').print('readyVar = ' + readyVar);
  }
  innerFn();
  innerFn();
});

这看起来像我们前面的许多例子,除了在这种情况下,外部函数是传递给$(document).ready()的回调函数。由于innerFn()是在它内部定义的,并且引用回调函数范围内的readyVar,因此innerFn()及其环境创建了一个闭包。我们可以通过注意readyVar的值在函数调用之间持续存在来看到这一点:readyVar = 1readyVar = 2

$(document).ready函数的持续时间内,它的所有局部变量都是活动的,并保持它们的值,该函数中的任何代码或任何嵌入函数都可以引用它们。虽然可以将其描述为函数闭包,但这更像是局部变量在函数中的工作方式。

如果在$(document).ready中,有一个嵌入函数在某处存储引用(如单击处理程序),那么将建立一个持久的函数闭包,并且readyVar的值将与任何嵌入引用的持续时间一样长。它本质上是垃圾收集。只要函数循环外的某个东西持有对循环内某个东西的引用,循环就保持存活。当循环执行完成,并且循环外没有任何嵌入函数引用到循环内的东西时,循环被垃圾收集并消失。

因为没有嵌入函数引用在你现在拥有的,它将被垃圾收集(例如销毁和释放),当它完成执行。

现在,如果您修改它以添加像这样的单击处理程序,那么您现在就有了对$(document).ready函数中具有单击处理程序函数的函数的持久引用。因为它仍然存在,即使在$(document).ready循环完成执行之后,它也不会被垃圾收集,而是作为函数闭包存在。

$(document).ready(function() {
  var readyVar = 0;
  function innerFn() {
    readyVar++;
    $('#example-9').print('readyVar = ' + readyVar);
  }
  innerFn();
  innerFn();
  $("#content").click(function(){  // external reference to within this function
      alert(readyVar);
  });
});

我从你的问题中感觉到你混淆了局部变量和函数闭包。这两者是相关的,但不是同一件事。局部变量在函数的生命周期内总是可用的。函数的生命周期是指它正在执行的时间,除非对其中的闭包的引用导致它持续的时间超过了这个时间。

您可能会发现这很有帮助:http://blog.morrisjohns.com/javascript_closures_for_dummies.html