在循环中添加事件

3

我所做的是使用循环在类上附加事件,并且索引值被用于事件处理程序代码中。这是我的代码:

var classElements=document.getElementsByClassName("a");
for(var i=0; i<4; i++)
{
    classElements[i].onClick=function(){
       alert("Clicked button : "+i);
    }
}

无论我点击哪个按钮,它都会弹出警告框:

点击的按钮:4

可能是什么问题呢?

1
你告诉它要弹出i,但是你一直在改变i的值,最终把它设为了4。 - Sampson
好的阅读材料:JavaScript闭包是如何工作的? - vcsjones
如果我想让它警报i,那么我应该怎么做呢? - Sourabh
2
@Sourabh 稍等,答案即将到来。这可能是你作为 JavaScript 程序员人生的关键时刻 ;) - Sampson
1
FYI:onClick 应该改为 onclick - user1106925
2个回答

4

JavaScript封闭了对象并在调用时稍后进行评估。在调用时,i等于4。

我认为您需要的是这样的:

var classElements=document.getElementsByClassName("a");
for(var i=0; i<4; i++)
{
    classElements[i].onClick=function(j) { 
       return function(){
          alert("Clicked button : "+j);
       };
    }(i);
}

编辑:使用命名函数显示代码,使代码更清晰

var classElements=document.getElementsByClassName("a");
for(var i=0; i<4; i++)
{
    var makeFn = function(j) { 
       return function(){
          alert("Clicked button : "+j);
       };
    };
    classElements[i].onClick = makeFn(i);
}

我不确定,但我认为当您在附加事件时传递参数时,JavaScript 会传递一个事件对象,而不是我们想传递的变量。 - Sourabh
我将一个参数传递给一个返回函数的函数。返回的函数是附加的函数。 - Lou Franco
如果是我,我会用一些外部括号包装 function(j)。关于如何/何时自动执行这样的函数可能存在一些歧义,而外部括号则使其明确无误。 - Matt
当你调用像e.onclick=function(eve){...}这样的函数时,实际上是将一个函数附加到e的onclick事件上,对吗?我认为eve是事件对象而不是变量,抱歉我还是没有理解你的答案。 - Sourabh
@Sourabh:function(j) {...会立即被调用,而return function(){...则被分配为处理程序。如果您使用命名函数而不是内联匿名函数,则更清晰。也许Lou会更新并提供那个解决方案。 - user1106925
你比我快了5秒,你的答案仍然更加完整 :) - vol7ron

2

为了捕获i的变化,您需要一个闭包。正如Lou所说,这是由于后评估造成的。

var classElements=document.getElementsByClassName("a");
for(var i=0; i<4; i++)
    classElements[i].onclick = (function(i){
          return function(){ alert("Clicked button : " + i) }; 
       })(i);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接