jQuery事件绑定按值传递
jQuery event binding pass by value
下面的页面显示了五个按钮,单击每个按钮都会收到警报'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>
JavaScript只有函数作用域,所以在您的示例中只有一个num
,它不断被修改,到调用click事件时,它等于五个。要解决这个问题,必须使用新的函数范围创建正确的闭包,如下所示:
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);
}
在循环中创建的事件处理程序函数有一个持久引用到创建它们的作用域内的变量,而不是在创建函数时对这些变量的复制。这就是闭包的工作方式(more: 闭包并不复杂)。所以所有的处理函数都引用同一个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);};
}
可以看到,在钩住click
事件并将其返回值传递给click
时,我们调用 buildHandler
。buildHandler
创建并返回一个函数,该函数关闭我们传递给它的参数val
。由于val
是我们想要警报的数字的副本,并且没有任何东西改变val
,因此函数按预期执行。
离题1:你在代码中创建了很多全局变量。全局名称空间已经非常拥挤了,我建议尽可能避免创建更多的全局名称空间。我将代码包装在函数中,这样变量就都是函数的局部变量:
<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
函数。更多: for..in
的神话与现实
改变这一行:
var btn=$('<button></button>').text(num).click(function(){alert($(this).text()});
您创建的所有click
处理程序都指向相同的全局变量num
,该变量在循环运行后为5,在您实际单击以触发处理程序并显示警报时仍为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做的事情,并有一个单独的处理程序构建函数,而不是像我那样内联地做。两者都可以,但是单独的处理程序构建器应该更有效(并且更容易阅读)。
试试这个
<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>
这个更简单:
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()?
- 将值动态绑定到jquery中的切换按钮
- 在extJS 4.2中,有没有一种方法可以将模型值动态绑定到表单
- 在函数中按值传递对象
- 变量/对象是否按值传递,为什么我不能在 javascript 中使用变量更改对象的属性
- Javascript :按值传递字符串
- 如何在角函数控制器中传递绑定值
- 如何使用 AngularJS 将值动态绑定到链接
- 敲除类的动态表达式值 - CSS 绑定
- 角度-引导-滑块默认值/双向绑定
- setTimeout 按值传递数组(在咖啡中)
- 在 JavaScript 中传递绑定对象方法
- JavaScript 处理参数按值传递
- 为什么这个数组是通过引用而不是按值传递的,我该如何改变它
- 按不同顺序绑定参数
- D3.js传递绑定函数似乎没有执行该函数
- 选项值数据绑定不起作用
- 通过按Enter触发绑定到HTML按钮的JavaScript函数.(不使用Tab键)
- Javascript函数的所有参数都只按值传递
- 值没有绑定到角自定义单选按钮组件中
- jQuery事件绑定按值传递