我对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'关键字来解决我的特定问题,但我仍然对这种行为背后的原因感到好奇。答案 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
。