javascript 在for循环中创建的Javascript多个动态addEventListener - 传递参数不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14177757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript multiple dynamic addEventListener created in for loop - passing parameters not working
提问by KDawg
I want to use event listeners to prevent event bubbling on a div inside a div with onclick functions. This works, passing parameters how I intended:
我想使用事件侦听器来防止带有 onclick 函数的 div 内的 div 上的事件冒泡。这有效,按照我的意图传递参数:
<div onclick="doMouseClick(0, 'Dog', 'Cat');" id="button_id_0"></div>
<div onclick="doMouseClick(1, 'Dog', 'Cat');" id="button_id_1"></div>
<div onclick="doMouseClick(2, 'Dog', 'Cat');" id="button_id_2"></div>
<script>
function doMouseClick(peram1, peram2, peram3){
alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3);
}
</script>
However, I tried to create multiple event listeners in a loop with this:
但是,我尝试使用以下方法在循环中创建多个事件侦听器:
<div id="button_id_0"></div>
<div id="button_id_1"></div>
<div id="button_id_2"></div>
<script>
function doMouseClick(peram1, peram2, peram3){
alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3);
}
var names = ['button_id_0', 'button_id_1', 'button_id_2'];
for (var i=0; i<names.length; i++){
document.getElementById(names[i]).addEventListener("click", function(){
doMouseClick(i, "Dog", "Cat");
},false);
}
</script>
It correctly assigns the click function to each div, but the first parameter for each, peram1
, is 3
. I was expecting 3 different event handlers all passing different values of i
for peram1
.
它正确地为每个 div 分配了点击功能,但每个 , 的第一个参数peram1
是3
。我期待 3 个不同的事件处理程序都传递不同的i
for值peram1
。
Why is this happening? Are the event handlers not all separate?
为什么会这样?事件处理程序不是都是分开的吗?
回答by elclanrs
Problem is closures, since JS doesn't have block scope (only function scope) i
is not what you think because the event function creates another scope so by the time you use i
it's already the latest value from the for
loop. You need to keep the value of i
.
问题是闭包,因为 JS 没有块作用域(只有函数作用域)i
并不是你想的那样,因为事件函数创建了另一个作用域,所以当你使用i
它时,它已经是for
循环中的最新值。您需要保留 的值i
。
Using an IIFE:
使用 IIFE:
for (var i=0; i<names.length; i++) {
(function(i) {
// use i here
}(i));
}
Using forEach
:
使用forEach
:
names.forEach(function( v,i ) {
// i can be used anywhere in this scope
});
回答by Stuart
As pointed out already the problem is to do with closures and variable scope. One way to make sure the right value gets passed is to write another function that returns the desired function, holding the variables within the right scope. jsfiddle
正如已经指出的,问题与闭包和变量范围有关。确保传递正确值的一种方法是编写另一个返回所需函数的函数,将变量保存在正确的范围内。提琴手
var names = ['button_id_0', 'button_id_1', 'button_id_2'];
function getClickFunction(a, b, c) {
return function () {
doMouseClick(a, b, c)
}
}
for (var i = 0; i < names.length; i++) {
document.getElementById(names[i]).addEventListener("click", getClickFunction(i, "Dog", "Cat"), false);
}
And to illustrate one way you could do this with an object instead:
并举例说明您可以使用对象执行此操作的一种方法:
var names = ['button_id_0', 'button_id_1', 'button_id_2'];
function Button(id, number) {
var self = this;
this.number = number;
this.element = document.getElementById(id);
this.click = function() {
alert('My number is ' + self.number);
}
this.element.addEventListener('click', this.click, false);
}
for (var i = 0; i < names.length; i++) {
new Button(names[i], i);
}
or slightly differently:
或略有不同:
function Button(id, number) {
var element = document.getElementById(id);
function click() {
alert('My number is ' + number);
}
element.addEventListener('click', click, false);
}
for (var i = 0; i < names.length; i++) {
new Button(names[i], i);
}
回答by olindk
It's because of closures.
这是因为关闭。
Check this out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake
看看这个:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake
The sample code and your code is essentially the same, it's a common mistake for those don't know "closure".
示例代码和你的代码本质上是一样的,对于不知道“闭包”的人来说,这是一个常见的错误。
To put it simple, when your create a handler function, it does not just accesses the variable i
from the outer environment, but it also "remembers" i
.
简单来说,当你创建一个处理函数时,它不仅会访问i
外部环境中的变量,还会“记住” i
。
So when the handler is called, it will use the i
but the variable i
is now, after the for-loop, 2.
因此,当处理程序被调用时,它将使用 ,i
但变量i
现在是,在 for 循环之后,2。
回答by jyore
Everything is global in javascript. It is calling the variable i
which is set to 3 after your loop...if you set i
to 1000 after the loop, then you would see each method call produce 1000 for i
.
在 javascript 中,一切都是全局的。它正在调用在i
循环后设置为 3的变量……如果i
在循环后设置为 1000,那么您将看到每个方法调用产生 1000 for i
。
If you want to maintain state, then you should use objects. Have the object have a callback method that you assign to the click method.
如果你想保持状态,那么你应该使用对象。让对象具有分配给 click 方法的回调方法。
You mentioned doing this for event bubbling...for stopping event bublling, you really do not need that, as it is built into the language. If you do want to prevent event bubbling, then you should use the stopPropagation()
method of the event
object passed to the callback.
你提到这样做是为了事件冒泡……为了停止事件冒泡,你真的不需要那个,因为它内置于语言中。如果你确实想防止事件冒泡,那么你应该使用传递给回调stopPropagation()
的event
对象的方法。
function doStuff(event) {
//Do things
//stop bubbling
event.stopPropagation();
}