4
window.onload = function() {
   var a = function(x) {
       console.log(x);
   };
   document.onclick = function() {
       a(1);
   };
   document.onkeyup = function() {
       a(2);
   };
};

我很清楚为什么会这样,但不知道如何。

window.onload ends ,a被销毁,但它引用的函数仍然可供事件处理程序使用,因为如果我理解正确的话,它是在更高的范围内声明的。

解释器是否在后台保留对该函数的隐藏引用,或者解释器是否以某种方式内联该函数?这种避免全局变量的代码是否有效?谢谢。

4

6 回答 6

1

window.onload结束时,a被摧毁……

这种假设是错误的。每当您在另一个函数中创建函数时,这些内部函数都会阻止垃圾收集器清理外部函数的范围。

推荐阅读:http ://www.ibm.com/developerworks/web/library/wa-memleak/

于 2013-02-04T08:17:06.077 回答
0

这不是您问题的完整答案,但如果有帮助... Javascript 中的对象生命周期通常通过引用计数来控制。

该语言实际上没有块作用域的概念(尽管它确实享有函数作用域)。只有当没有引用时,后台 GC 才会自动清理对象。因此,对象的行为a本质上是“安全的”:当函数作用域结束时,一个引用被删除,但另一个引用仍然存在。

更详细的答案必须复杂地探索特定 Javascript 引擎的实现,可能比我们在这里的时间或空间要详细得多。

于 2013-02-04T08:09:07.117 回答
0

javascript 变量中的函数或对它们的引用是一种对象,就像常规对象一样,持有对它们的引用的函数或变量在没有对它们的引用之前不会被垃圾收集。在您的特定情况下,您创建了几个a()比处理程序持续时间更长的引用.onload()。因此,变量的a持续时间也比函数长得多。这个概念被称为“闭包”。

如果您在 Google 中搜索术语“javascript 中的闭包”,您会发现许多关于该主题的有用文章,例如这篇文章。

于 2013-02-04T08:11:38.727 回答
0

当您在处理程序中声明第一个函数时,JavaScript 会自动创建范围或上下文对象window.onload;这个范围对象保留了变量a,有效地使它对你的两个匿名函数都是专有的。

这种技术通常用于信息隐藏和避免创建全局变量。代码运行后onload,没有其他代码可以访问a.

于 2013-02-04T08:43:25.270 回答
0

这被称为“关闭”。简而言之,它意味着“一个函数可以访问定义它的范围内的所有变量”。

在您的示例中,两个处理程序是在window.onload函数内部定义的,因此它可以访问a也在该范围内的 。

是的,解释器将所有闭包保存在内存中。(afaik)
我不是专业程序员,所以我没有太多权限。但我通常这样做是为了避免全局变量。

在 MDN 上关闭

于 2013-02-04T08:06:33.747 回答
0

解释器是否在后台保留对该函数的隐藏引用,或者解释器是否以某种方式内联该函数?

对于所有 javascript 引擎,这无法在全球范围内得到解答。但是解析器很可能必须为您在和a上定义的匿名函数保留对您的函数的引用。所以不会马上销毁,只能通过javascript变量作用域的限制才能访问。document.onclickdocument.onkeyupa

这就是为什么闭包会导致内存泄漏的原因,因为引擎很难真正a正确地取消引用。(这是IE 引擎的问题,如果不小心处理仍然存在)。而且由于您无法a手动取消引用,因为您无法访问变量,因此无法快速修复由这种模式引起的内存泄漏。

您的示例也不闭包,因为它不返回函数,但它处理相同类型的变量范围问题,因为它引用了a不共享相同范围(document.onclickdocument.onkeyup)的函数内部的局部变量。

我高度怀疑没有引擎会尝试内联函数a,因为这会不必要地复制函数对象。pointer一旦引用计数降至 0(在您的示例中,当document.onclickdocument.onkeyup被取消引用(设置为nullor )时,它很可能与 a和提到的引用计数一起被允许轻松销毁undefined

这种避免全局变量的代码是否有效?

避免全局变量总是好的,所以总的来说:是的,这是避免全局变量的有效方法。每个好的引擎也应该销毁a一次document.onclick并被document.onkeyup取消引用。

于 2013-02-04T08:16:45.760 回答