循环中带参数的函数调用添加事件监听器

5
问题:我想通过按钮的点击事件调用一个名为“test”的函数并传递参数。 使用 addEventListener('click', test); 可以工作。 使用 addEventListener('click', test(parameter)); 函数会在加载时自动激活,而不是在点击按钮时。 问题:如何传递参数?
//create 3 button (n is a counter):
    var btn = document.createElement("INPUT");
        btn.setAttribute("id", "demo"+n);
        btn.setAttribute("type", "button");
        btn.setAttribute("value", ("click"));
        document.body.appendChild(btn);

不带参数的调用是正常的:

function test(m) {
    alert("YOU CLICKED ME!");
}

var m=0;
while(m!=3){
        document.getElementById("demo"+m).addEventListener("click", test);
        m=m+1;
}   
使用参数无法工作(函数立即激活):
function test(m) {
    alert("YOU CLICKED ME!"+m);
}

var m=0;
while(m!=3){
    document.getElementById("demo"+m).addEventListener("click", test(m));
            m=m+1;
}   
4个回答

5

将您的函数包装在另一个函数中,以避免立即调用它。

document.getElementById("demo"+m).addEventListener("click",(function(x){
    return function(){
        test(x);
    }
})(m));
在您的情况下,addEventListener期望一个函数对象,因此您不能在函数前面使用括号,因为它会调用该函数并传递返回值。因此,您需要返回调用test函数的函数对象(使用匿名函数来避免javascript函数的闭包属性)。 编辑: 返回test的包装函数使用匿名函数的原因 我们无法传递
function(){
    test(m);
}

直接添加addEventListener。

在JavaScript中,每个函数对象都记得它们词法作用域之外的环境( 在我们的情况下是变量m )。如果您只是在同一个环境( 变量m )中创建不同的函数(例如在while循环中),那么它们将引用同一个环境。

您需要使用函数工厂来避免在循环中创建闭包,如上所述。


这样做是不行的,你总是会在 m 中得到循环中的最后一个值。 - jcubic
是的,忘记了闭包。谢谢,已经修复。 - bugwheels94

2

试试这个:

function test(m) {
    alert("YOU CLICKED ME!"+m);
}

var m=0;
while (m!=3) {
    (function(m) {
        document.getElementById("demo"+m).addEventListener("click", function() {
            test(m);
        });
    })(m);
    m=m+1;
}   
这将为循环内的变量创建新的作用域。

2

为什么addEventListener('click', test(parameter))无法工作的解释

addEventListener函数可以接受两个参数,事件类型和接收事件的侦听器对象。在大多数情况下,侦听器对象只是一个JavaScript函数。

因此,当您使用

addEventListener('click', test);
你正在将字符串click作为事件类型传递,并将函数test作为监听器使用,这正是你所期望的。 但当你使用时:
addEventListener('click', test(parameter));
监听器实际上是表达式test(parameter)的计算结果。由于test(parameter)是一个函数调用,你实际上传递的是test(parameter)返回的内容,即'undefined',因为test函数没有返回任何东西。这就是为什么test会立即被调用——它需要被调用来获取返回值作为addEventListener函数调用的参数。因此,如果要在事件发生时执行带有自定义参数的函数,可以使用其他人提出的匿名函数方法。

0
您需要使用所谓的“高阶函数”来构建test函数的不同版本:
// this is a high order function, since it returns a function
function buildTestFunction(m) {
  return function () {
    alert("YOU CLICKED ME!"+m);
  };
}

var m=0;
while(m!=3){
  var test = buildTestFunction(m);
  document.getElementById("demo"+m).addEventListener("click", test);
  m=m+1;
}

顺便提一下,为了更清晰明了,您可能想在这里使用一个for循环。

for (var m = 0; m < 3; m++) { ... }

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