JavaScript for循环索引的陌生感

时间:2010-05-10 14:23:53

标签: javascript for-loop onclick

我对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 个答案:

答案 0 :(得分:15)

for循环中有a very common closure problem

封闭在闭包中的变量共享相同的单个环境,因此在执行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文章以获得简要介绍:


注意:我还建议不要在var循环中使用for,因为这可能会让你相信i变量具有块范围,而另一方面i变量就像buttons变量一样,在函数范围内。

答案 1 :(得分:9)

您需要存储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作为该参数传递。这将在单独的范围中创建一个新变量,从而保存该特定迭代时的值。

答案 2 :(得分:0)

这是执行问题的顺序

How to assign event callbacks iterating an array in javascript (jQuery)

基本上,点击处理程序在循环退出后很快就会访问i,因此i等于2