【问题标题】:How can I work around the Javascript closures?如何解决 Javascript 闭包问题?
【发布时间】:2011-09-09 03:12:19
【问题描述】:

考虑一下 JavaScript 的这个小 sn-p:

for(var i in map.maps)
{
    buttons.push($("<button>").html(i).click(function() { alert(i); }));
}

它为map.maps 对象(它是一个关联数组)中的每个字段创建一个按钮。我将索引设置为按钮的文本,并将其设置为提醒索引。显然,人们希望所有按钮在单击时都会提醒它自己的文本,但所有按钮都会在单击时提醒 map.maps 对象中的 final 索引的文本。

我认为这种行为是由 JavaScript 处理闭包的简洁方式引起的,从创建它们的闭包返回并执行函数。

我能想象解决这个问题的唯一方法是将索引设置为按钮对象上的数据并从点击回调中使用它。我也可以在我的buttons 对象中模仿map.maps 索引,并使用indexOf 在点击时找到正确的索引,但我更喜欢前一种方法。

我在答案中寻找的是确认我正在以正确的方式做事,或者是关于我应该如何应该做的建议。

【问题讨论】:

标签: javascript jquery function closures


【解决方案1】:

拥抱闭包,不要绕过它们。

for(var i in map.maps)
{
    (function(i){
        buttons.push($("<button>").html(i).click(function() { alert(i); }));
    })(i);
}

您需要包装使用您的 var i 的代码,以便它在一个单独的闭包中结束,并且该值保存在该闭包的本地 var/param 中。

在 lonesomeday 的回答中使用单独的函数可以稍微隐藏这种关闭行为,但同时更清晰。

【讨论】:

  • 我的代码(非常稍微)更快,因为该函数只创建一次。然而,效果完全相同。
【解决方案2】:

如果将变化的值作为参数传递给另一个函数,则该值将被锁定:

function createButton(name) {
    return $("<button>").html(name).click(function() { alert(name); });
}

for (var i in map.maps) {
    buttons.push(createButton(i));
}

【讨论】:

    【解决方案3】:
    for(var i in map.maps){
        (function(i){
             buttons.push($("<button>").html(i).click(function() { alert(i); }))
        })(i);
    }
    

    在您的情况下关闭失败的原因是即使在绑定函数后它的值仍然更新,在这种情况下是事件处理程序。这是因为闭包只记住对变量的引用,而不是绑定时的实际值。

    使用执行的匿名函数,您可以强制执行正确的值,这通过将 i 传递给匿名函数来实现,因此在匿名函数的范围内重新定义了 i。

    【讨论】:

      【解决方案4】:

      这是做你想做的事情的最优雅的方式:

      var buttons = myCharts.map(function(chart,i) {
          return $("<button>").html(chart).click(function(event){
              alert(chart);
          });
      }
      

      需要闭包来优雅地编写 javascript 代码,并且不应该绕过它们。否则你不能做嵌套 for 循环之类的事情(没有非常黑客)。当你需要一个闭包时,使用一个闭包。不要害怕在函数内部定义新函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-05
        • 1970-01-01
        • 1970-01-01
        • 2020-04-27
        • 2021-03-02
        • 2020-10-29
        • 2021-06-12
        相关资源
        最近更新 更多