首页 >web前端 >js教程 >为什么 Javascript 循环会导致事件处理程序出现意外行为?

为什么 Javascript 循环会导致事件处理程序出现意外行为?

DDD
DDD原创
2024-12-22 06:26:38321浏览

Why Do Javascript Loops Cause Unexpected Behavior in Event Handlers?

重访 Javascript 臭名昭著的循环问题

Javascript 中臭名昭著的循环问题继续困扰着开发人员。考虑以下代码片段:

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function () {
            alert(i);
        };
        document.body.appendChild(link);
    }
}

此代码旨在创建 5 个链接,每个链接都有一个显示当前链接 ID 的 onClick 事件。然而,当点击这些链接时,它们都显示“链接 5”。

这个问题的根本原因在于 Javascript 的函数级作用域。当循环完成时, i 变量保留值 5。这是因为 Javascript 函数在其词法环境中是封闭的,这意味着它们可以访问周围范围中定义的变量。

此问题的解决方法是引入一个闭包,捕获每次迭代的 i 的当前值:

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function (num) {
            return function () {
                alert(num);
            };
        }(i);
        document.body.appendChild(link);
    }
}

在此代码中,为每个链接创建一个新的函数对象。它有自己的作用域和一个局部变量 num,它被赋予 i 的当前值。执行内部函数时,它引用闭包的 num 变量,该变量保留了循环中分配的正确值。

虽然这种方法很有效,但在创建新函数时会带来性能损失对于每个事件侦听器。更高效的替代方案是使用 DOM 节点本身来存储数据:

function linkListener() {
    alert(this.i);
}

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = linkListener;
        document.body.appendChild(link);
    }
}

通过将 i 值直接存储在 DOM 节点上,我们消除了对闭包的需要,从而提高了代码效率。

以上是为什么 Javascript 循环会导致事件处理程序出现意外行为?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn