带有绑定点击事件的Javascript循环始终返回最后结果

时间:2011-12-26 19:30:24

标签: javascript jquery loops

我有一个在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);

}

我想我明白为什么会这样,但不知道我应该如何处理它。

2 个答案:

答案 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);

}