以下页面显示五个按钮,点击每个按钮获取警报'5'。我想当我点击第一个按钮时,我会收到警报'1',第二个按钮'2'......等等。
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
</head>
<body>
<div id="nums"></div>
<script type="text/javascript">
var nums = [1,2,3,4,5];
for(var i in nums){
var num = nums[i];
var btn=$('<button></button>').text(num).click(function(){alert(num);});
$('#nums').append(btn);
}
</script>
</body>
</html>
答案 0 :(得分:5)
JavaScript只有函数作用域,因此在您的示例中只有一个num
,它会一直被修改,并且在调用click事件时,它等于五。要解决这个问题,您必须使用新的函数范围创建正确的closure,如下所示:
var nums = [1,2,3,4,5];
var createClick = function (num) { return function() { alert(num); }; };
for(var i in nums){
var num = nums[i];
var btn=$('<button></button>').text(num).click(createClick(num));
$('#nums').append(btn);
}
答案 1 :(得分:3)
您在循环中创建的事件处理程序函数对创建它们的范围中的变量具有持久引用,而不是这些变量的副本当函数创建时这就是闭包的工作原理(更多:Closures are not complicated)。因此,所有处理程序函数都引用相同的num
变量,并且它们在click
事件发生时引用它。从那时起,它是5
(它被分配的最后一个值),你最终会向所有人发出警告5
。
如果您希望事件处理程序在创建处理程序时引用num
,则必须让处理程序关闭不会更改的内容。通常的方法是使用一个构建处理函数的函数,并使处理函数靠近该构建器函数的参数:
var nums = [1,2,3,4,5];
for(var i in nums){
var num = nums[i];
var btn=$('<button></button>').text(num).click(buildHandler(num));
$('#nums').append(btn);
}
function buildHandler(val) {
return function(){alert(val);};
}
正如您所看到的,我们在挂钩buildHandler
事件时将调用 click
并将其返回值传递给click
。 buildHandler
创建并返回一个关闭val
的函数,我们传递给它的参数。由于val
是我们希望它提醒的号码的副本,并且没有任何变化val
,因此这些功能会按照需要执行。
非主题1 :您在该代码中创建了许多全局变量。全局命名空间已经非常拥挤,我建议尽可能避免创建更多全局变量。我将该代码包装在一个函数中,以便varibles都是该函数的本地代码:
<script>
(function() {
var nums = [1,2,3,4,5];
for(var i in nums){
var num = nums[i];
var btn=$('<button></button>').text(num).click(buildHandler(num));
$('#nums').append(btn);
}
function buildHandler(val) {
return function(){alert(val);};
}
})();
</script>
它做同样的事情(我们定义函数,然后立即调用它),但不创建全局i
,num
,nums
和btn
变量。
非主题2 :您已将for..in
与数组一起使用而未进行任何检查,以确保您只处理数组索引。 for..in
不循环遍历数组索引;它遍历对象属性名称。编写for..in
循环就像它们循环遍历数组索引一样,会在某个阶段咬你。只需使用普通的for
循环或进行必要的检查或使用jQuery的each
函数。更多:Myths and realities of for..in
答案 2 :(得分:2)
更改此行:
var btn=$('<button></button>').text(num).click(function(){alert($(this).text()});
答案 3 :(得分:2)
您创建的所有click
个处理程序都会引用相同的全局变量num
,它在循环运行后为5,在您实际执行单击以触发处理并显示警报。
两种解决方法如下:
(1)鉴于您已将数字设置为按钮的文本,请在处理程序中使用该数字,如下所示:
// jQuery will set 'this' for you when it calls your click handler
[...].click(function(){ alert($(this).text()); });
(2)创建一个闭包,以便为每个处理程序保留num
的各个值:
[...].click((function(closureNum){
return function(){ alert(closureNum); }
})(num));
编辑:刚看到其他答案。为了更好地改变我的第二个选项,我建议做T.J.和FishBasketGordo做了并且有一个单独的处理程序构建函数,而不是像我一样内联。要么应该工作,要么单独的处理程序构建器应该更有效(并且可以说,更容易阅读)。
答案 4 :(得分:0)
试试这个
<script type="text/javascript">
var nums = [1,2,3,4,5];
for(var i in nums){
var num = nums[i];
var btn=$('<button></button>').text(num).click(function(){alert(nums[i]);});
$('#nums').append(btn);
}
</script>
答案 5 :(得分:0)
这更简单:
var nums = [1,2,3,4,5];
$.each(nums, function(index, value){
var btn=$('<button></button>').text(value).click(function(){alert(value);});
$('#nums').append(btn);
});
由于您的页面中已经有jquery,为什么不使用$ .each()?