【问题标题】:Closure - when a new closure is created what happens to the existing one?闭包——当一个新的闭包被创建时,现有的闭包会发生什么?
【发布时间】:2011-08-17 01:35:15
【问题描述】:
document.getElementById("innbutt").onclick = (function(){
    var newvar = "hello"; 
    return function(){
        alert(newvar);
    }
})();

当我们不断点击innbutt 时,新的闭包会不断创建。

那么,旧的会发生什么?
1)它会被删除吗?或
2) 它是否留在内存中?

编辑:

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function (num) {
            return function () {
                alert(num);
            };
        }(i);
        document.body.appendChild(link);
    }
}
window.onload = addLinks;

来源:javascript scope and closures
在这种情况下,link.onclick 处理程序只创建了 1 个闭包?

【问题讨论】:

  • “当我们不断点击 innbutt 时,新的闭包不断被创建。”不,匿名的自调用函数在分配给….onclick 后立即执行并返回一个新的匿名函数(带有alert),它实际上分配给….onclick
  • @Marcel:你能看看我现在发布的代码,看看是否只会为事件处理程序创建 1 个闭包吗?
  • 你应该在一个新问题中提出这个问题,这样这里的每个人都会被注意到并可以回答。例如,如果我刚刚去度假并且两周没有看 SO,你会怎么做? ;-) 无论如何,现在您正在创建五个闭包,每个事件处理程序一个。

标签: javascript memory closures


【解决方案1】:

只创建一个闭包

因为你误解了事件处理器的概念。

document.getElementById("innbutt").onclick = (function(){
    var newvar = "hello"; 
    return function(){
        alert(newvar);
    }
})();

可以说等价于:

document.getElementById("innbutt").onclick = function() {
    alert("hello");
};

因为在第一种情况下,立即执行的函数返回带有alert 的匿名函数,并且被分配给onclick 处理程序。每当您单击按钮时,都会执行此特定的匿名函数。不会像您错误地认为的那样处理新的 onclick 处理程序分配。

【讨论】:

  • @Robert:你能看看我现在发布的代码,看看是否只会为事件处理程序创建 1 个闭包吗?
  • @Anish:是的,每个链接都只会分配一次自己的onclick 处理程序,每次单击它都会提醒一个数字。 重要提示:您还应该在链接点击处理程序中return false 以防止默认链接浏览器行为(通常获取新内容或在页面内跳转)。
  • @Robert:所以每个链接都有自己独立的闭包,对吧?如果有 5 个链接,会创建 5 个闭包?
  • @Anish:没错。我不了解浏览器 Javascript 引擎及其内部优化(因为理论上可以重用您的匿名函数),但每个链接都有自己的关闭单击处理函数。
【解决方案2】:

首先要注意的是,每次单击 innbutt 时都不会重新创建包含 newvar 定义的原始闭包。它执行了一次,并且该闭包中的命名空间一直存在,直到您删除对执行警报的内部函数的所有引用。因此,要回答您的第一个问题,关闭不会被删除。要回答您的第二个问题,闭包中的命名空间会一直存在,直到您删除对分配给 innbutt 的 onclick 函数的所有引用。换句话说,如果您将 onclick 设置为 null,则闭包将不再保留在内存中,除非在此之前将该函数分配给另一个变量。

这是一个与您的示例类似的示例。这个例子有一个立即执行的闭包,然后返回一个可以访问该持久闭包的命名空间的函数:

secrets = (function() {
  var mySecrets = {};
  return function(name, value) {
    if(arguments.length < 2)
      return mySecrets[name + ""];
    mySecrets[name + ""] = value;
  };
})();

// Set my name.
secrets("my name", "Chris West");

// Set my friend's name.
secrets("my friend's name", "John Jacob");

// Get my name and my friend's name.
alert("My name is " + secrets("my name") + ".\n"
  + "My friend's name is " + secrets("my friend's name") + ".");

// Alias the secrets function.
fnSecrets = secrets;

// Remove one reference to the secrets function.
secrets = null;

// Remove the second reference to eliminate the closure from memory.
fnSecrets = null;

请注意,secrets 函数实际上是在闭包内返回的函数。此外,这个函数可以访问 mySecrets,它是闭包中的一个变量。由于我将 fnSecrets 编写为别名 secret,一旦我将 secrets 清空,闭包仍然存在,直到 fnSecrets 被清空。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 2011-11-17
    相关资源
    最近更新 更多