带有绑定click事件的Javascript循环总是返回最后的结果

Javascript loop with binded click event always returning last result

本文关键字:返回 最后的 结果 循环 Javascript 绑定 click 事件      更新时间:2023-09-26

我有一个for循环在javascript中运行。在这个循环中,我创建了一个列表项并将一个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);
}

我想我知道为什么会发生这种情况,但不知道该如何处理。

这是一个经典的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成为全局变量。

您需要打破对e的闭包。

因为你使用jQuery,最简单的方法是用jQuery的data函数保存e的当前值。由于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);
}