我如何解决Javascript闭包问题?

时间:2011-06-06 09:01:05

标签: javascript jquery function closures

考虑这个小小的JavaScript片段:

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

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

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

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

我在答案中寻找的是确认我正在以正确的方式进行,或者建议我应该这样做。

4 个答案:

答案 0 :(得分:9)

拥抱封闭物,不要在它们周围工作。

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

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

在lonesomeday的回答中使用一个单独的函数可以隐藏这个闭包行为,但同时也更加清晰。

答案 1 :(得分:4)

如果将更改值作为参数传递给另一个函数,则该值将锁定在:

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

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

这是您尝试做的最优雅的方式:

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

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