我有一个在javascript中运行的for循环。在这个循环中,我创建了一个列表项并将click事件绑定到它。当我单击此列表项时,我希望它使用当前循环对象中的数据作为参数调用函数。
问题是,无论我点击什么列表项。作为参数传递的数据是我循环的对象的最后一个元素,而不是当前被点击的对象。
for(e in data) {
var suggestItem = $('<li>'+ data[e]['name'] +'</li>');
suggestItem.click(function() {
$(this).addClass('activeSuggestion');
suggestSelect(suggestField, data[e]);
});
suggestList.append(suggestItem);
}
我想我明白为什么会这样,但不知道我应该如何处理它。
答案 0 :(得分:5)
这是一个经典的Javascript闭包问题。当触发click事件时(当你点击某些东西时),循环已经完成执行。 e
的值是data
中的最后一个键。该问题的解决方案是在循环内部创建一个新的范围。
for(var e in data) {
(function(datum) {
suggestList.append(
$('<li>' + datum.name + '</li>')
.click(function() {
$(this).addClass('activeSuggestion');
suggestSelect(suggestField, datum);
});
);
})(data[e]);
}
Javascript是函数作用域,因此每当遇到新函数时,都会创建一个新作用域。上面的代码将data[e]
的值“捕获”到datum
中,因为它将它作为参数传递给函数。另一种编码方式可能不那么容易混淆:
for(var e in data) {
(function() {
var datum = data[e];
suggestList.append(
$('<li>' + datum.name + '</li>')
.click(function() {
$(this).addClass('activeSuggestion');
suggestSelect(suggestField, datum);
});
);
})();
}
它不会将参数传递给函数,但由于Javascript是函数作用域,因此每次触发click事件时,它都会查找datum
的分配位置。
另请注意for(VAR e in data)
,它会阻止e
成为全局变量。
答案 1 :(得分:3)
你需要打破e
的封闭。
由于您使用的是jQuery,最简单的方法是使用jQuery的e
函数保存data
的当前值。由于JavaScript中的所有函数参数都是按值传递的,因此有效地打破了闭包;现在,您的单击处理程序将在创建处理程序时使用e
的值,而在循环结束时不会保持值e
。
for(e in data) {
var suggestItem = $('<li>'+ data[e]['name'] +'</li>');
suggestItem.data('savedE', e).click(function() {
$(this).addClass('activeSuggestion');
suggestSelect(suggestField, data[$(this).data('savedE')]);
});
suggestList.append(suggestItem);
}