JavaScript for 循环索引奇怪

IT技术 javascript for-loop onclick
2021-01-15 11:43:31

我对 JS 比较陌生,所以这可能是一个常见问题,但是在处理 for 循环和 onclick 函数时我注意到一些奇怪的事情。我能够用这段代码复制这个问题:

<html>
<head>

<script type="text/javascript">
window.onload = function () {
    var buttons = document.getElementsByTagName('a');
    for (var i=0; i<2; i++) {
        buttons[i].onclick = function () {
            alert(i);
            return false;
        }
    }
}

</script>

</head>

<body>
<a href="">hi</a>
<br />
<a href="">bye</a>

</body>

</html>

单击链接时,我希望得到“0”和“1”,但我却得到“2”。为什么是这样?

顺便说一句,我设法通过使用“this”关键字解决了我的特定问题,但我仍然很好奇这种行为背后的原因。

3个回答

循环中遇到了一个非常常见的闭包问题for

封闭在闭包中的变量共享同一个环境,所以当onclick回调被执行时,循环已经运行,i变量将指向最后一个条目。

你可以用更多的闭包来解决这个问题,使用函数工厂:

function makeOnClickCallback(i) {  
   return function() {  
      alert(i);
      return false;
   };  
} 

var i;

for (i = 0; i < 2; i++) {
    buttons[i].onclick = makeOnClickCallback(i);
}

如果您不熟悉闭包的工作原理,这可能是一个非常棘手的话题。您可以查看以下 Mozilla 文章进行简要介绍:


注意:我还建议不要varfor循环使用,因为这可能会欺骗您相信该i变量具有块作用域,而另一方面,该i变量就像buttons变量一样,作用于函数内。

您需要存储i变量的状态,因为在事件触发时,范围状态i已增加到最大循环计数。

window.onload = function () {
    var buttons = document.getElementsByTagName('a');
    for (var i=0; i<2; i++) {
        (function (i) {
            buttons[i].onclick = function () {
                alert(i);
                return false;
            }
        })(i);
    }
}

上面的示例创建了一个带有单个参数的匿名函数,i然后将i其作为该参数传递来调用。这会在单独的作用域中创建一个新变量,保存该特定迭代时的值。

不建议在循环中创建函数
2021-03-28 11:43:31
:sigh:是的,我想我是迂腐。所以起诉我。带着你的性能、你的编译器和你的“我是对的,我有 126k 代表”和你想要的一切的正确性和性能在你完美的小世界里欢腾。
2021-03-29 11:43:31
@Ryan:我不确定这是迂腐还是混乱。您正在重复 JSLint/JSHint 警告,而没有花时间了解它的含义。查看文档,了解不应在循环中创建的函数示例。IIFE 是可以接受的,因为它在某些情况下几乎是唯一的选择,直到let得到普遍支持。接受的答案也在循环中创建函数,但那里没有否决票或评论?
2021-04-10 11:43:31
@Ryan:所以你当时很迂腐,因为你对微优化投了反对票。甚至不是真正的,因为它没有考虑编译器自己的优化。在 Chrome 的控制台中,IIFE 在超过 100 万次操作时以大约 100 毫秒的速度出现(我鼓励您检查它)。这甚至不重要,因为问题是从i=0循环的2,所以差异将是不可估量的。恭喜你,你是交通官员,因为他的罚单过期 1 秒后才回到他的车,你会向他处以停车罚款。
2021-04-10 11:43:31
好的,让我澄清一下:您正在循环中创建两个函数。IIFE 和单击处理程序。公认的答案是在循环中创建一个函数:单击处理程序。因此,公认的答案将低效率降至最低,而您的答案则将它们最大化。
2021-04-13 11:43:31

这是一个执行顺序问题

如何在javascript(jQuery)中分配迭代数组的事件回调

基本上,单击处理程序i在循环退出后访问良好,因此i等于2

是的,这就是为什么我链接到我的一篇关于关闭的帖子。
2021-04-02 11:43:31
这也是一个范围问题,i在它不明显的时候徘徊。
2021-04-14 11:43:31