【问题标题】:Number value wrong in event bound through a for loop通过 for 循环绑定的事件中的数值错误
【发布时间】:2013-05-15 12:55:13
【问题描述】:
var rows = document.getElementsByClassName('row');
for (var i = 0, l = rows.length; i < l; i++) {
    if (i % 2 === 0) {
        $(rows[i]).click(function () {
            alert('I am line number ' + i);
        }
    }
}

嗨, 我如何获得每一行的实际行号?因为当我在偶数行上触发点击事件时,我得到的只是上限值(即:rows.length = 7,i 将是 6 每点击一行)。

【问题讨论】:

    标签: javascript for-loop alert


    【解决方案1】:

    问题是在click 事件被触发时,i 变量已经被循环迭代改变了。 理论上您可以使用闭包来使事情正常进行,即

    for (var i = 0, l = rows.length; i < l; i++) {
        if (i % 2 === 0) {
            (function(i) {
                $(rows[i]).click(function() {
                    alert("I am line number " + i);
                });
            )(i);
        }
    }
    

    实际上,如果你使用jQuery(我从代码中了解到),使用:even选择器会更容易:

    $(".row:even").click(function() {
        alert("I am line number " + $(".row").index(this));
    });
    

    【讨论】:

    • 啊,你打败了我!很好的答案。
    • 注意:.index()O(n),而不是 O(1)。此外,只有当所有元素都是同一父级的子级时,它才会按预期工作。
    • @Alnitak 是的。这只是如何获取它的索引的示例。如果有速度限制,带有一个 for 循环的纯 JS 将完美地完成这项工作。 UPD:现在索引将被正确计算。
    • 谢谢你的解释,现在明白了!
    • 仅供参考,这里的第一个代码示例缺少一个结束大括号来关闭 "(function(i) {"
    【解决方案2】:

    您得到错误数字的原因是您正在创建的事件处理函数获得了对i 变量的持久引用不是副本从它们创建时开始。

    解决这个问题的方法是让处理程序关闭一些不会改变的东西。这里有三种方法可以做到这一点,第一种是特定于 jQuery 的(看起来你正在使用 jQuery):

    jQuery 的each

    看起来您正在使用 jQuery,在这种情况下,您可以使用它的 each 来获取要使用的不会改变的索引:

    var rows = $(".row");
    rows.each(function(index) {
        if (index % 2 === 0) {
            $(this).click(function() {
                alert('I am line number ' + index);
            });
        }
    });
    

    现在,事件处理函数关闭了对我们提供给 each 的函数的调用的 index 参数,并且由于 index 参数永远不会改变,您会在警报中看到正确的数字。

    使用构建器函数

    (非 jQuery)您可以使用构建器函数解决此问题:

    var rows = document.getElementsByClassName('row');
    for (var i = 0, l = rows.length; i < l; i++) {
        if (i % 2 === 0) {
            $(rows[i]).click(buildHandler(i));
        }
    }
    function buildHandler(index) {
        return function () {
            alert('I am line number ' + index);
        };
    }
    

    这里,事件处理函数关闭了buildHandler 中的index 参数,并且由于index 参数永远不会改变,您会在警报中看到正确的数字。

    forEach

    (非 jQuery)您还可以使用 ES5 的 forEach 函数(这是您可以在 ES5 之前的环境中填充的 ES5 功能之一)来解决这个问题:

    var rows = document.getElementsByClassName('row');
    Array.prototype.forEach.call(rows, function(row, index) {
        if (index % 2 === 0) {
            $(row).click(function () {
                alert('I am line number ' + index);
            });
        }
    });
    

    这与上面两个的工作方式相同,通过关闭 index,这不会改变。

    【讨论】:

    • @Alnitak:不一定。这可以是使用$ 并提供click 的其他几个小库中的任何一个。我会是 is jQuery,但这并不意味着它是。 (如果发生这种情况他们不使用jQuery,那么其他选项对于发现此问题的人们将很有用。傻瓜。)
    • @Alnitak:这三个都是基于闭包的答案。
    猜你喜欢
    • 2021-06-15
    • 2013-01-22
    • 2022-01-20
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    相关资源
    最近更新 更多