提问者:小点点

带有参数的事件侦听器


我想用JavaScript将参数传递给事件侦听器。 我已经找到了解决方案,但我不明白它们为什么或如何起作用,以及为什么其他解决方案不起作用。

我有一个C/C++背景,但是在Javascript中函数的执行有很大的不同。 你能帮我理解下面的例子是如何和为什么起作用或不起作用的吗?

如果没有参数,代码可以正常工作:

var clicker = document.getElementById("mainNavToggle");
clicker.addEventListener("click", eventFunction);

function eventFunction()
{
  console.log("works");
}

如果我在eventListener上包含括号,那么函数只执行一次而不触发事件,然后什么也不做:

var clicker = document.getElementById("mainNavToggle");
clicker.addEventListener("click", eventFunction());

function eventFunction()
{
  console.log("works");
}

我想这是因为函数是在eventListener处调用的,这不允许eventListener函数稍后调用eventFunction。

当我想用EventFunction传递参数时。 以下情况不起作用:

var clicker = document.getElementById("mainNavToggle");
clicker.addEventListener("click", eventFunction("works"));

function eventFunction(myStr)
{
    console.log(myStr);
}

它在不触发事件的情况下调用eventFunction,然后当事件触发时什么也不做,这与之前的行为相同。 到目前为止我想我能理解。

为了在事件函数中正确传递参数,我找到了以下代码。 以下解决方案工作良好:

var clicker = document.getElementById("mainNavToggle");
clicker.addEventListener("click", eventFunction("works"));

function eventFunction(myStr)
{
  function func(event, myStr)
  {
    console.log(myStr);
  }

  return function(event) { 
    func(event,myStr) 
  };
}

我注意到的第一件事是这个eventFunction不是立即调用的。 这是为什么?

但是,我对参数如何在每个函数中传递感到困惑。 我知道“Works”文字是在EventFunction上传递给myStr的。 但是,在函数func中,EventFunction没有传递一个额外的事件参数。

还有,为什么eventFunction需要返回另一个函数,该函数带有一个内部调用func函数的参数?

还请注意,我希望向eventFunction传递不具有全局作用域的参数,否则就不需要传递参数。


共2个答案

匿名用户

让我们一步一步来解剖这个。

一般信息

.AddEventListener函数/方法包含2个(或3个)参数:

  • 一个字符串,具有事件类型/名称的值(例如“click”)
  • 指向函数的指针,该函数应在事件发生时执行
  • 一个布尔值,指定应使用事件冒泡还是事件传播。 此参数是可选的,可以省略。

实施例1

在第一个示例中,您将一个字符串(“Click”)和一个指向函数(EventFunction)的指针传递给.AddEventListener。 一切按预期工作,事件发生,函数执行。

实施例2

在本例中,您将字符串未定义传递给.AddEventListener,这不是.AddEventListener所期望的。 您可能会问自己“我什么时候传入了undefined?”。 在执行EventFunction之后添加了参数(),就会发生这种情况。 在这里,JS中的语法与大多数其他语言中的语法相等,在函数的右侧添加parens将执行该函数。

因为EventFunction不显式返回任何内容,所以它自动返回undefined。 因此,这就是.AddEventListener得到的:

clicker.addEventListener("click", undefined)

但是,由于您执行了EventFunction,它将“it Worked”记录到控制台一次。

实施例3

此示例失败的原因与示例2失败的原因相同。

实施例4

最后一个示例中的代码可以工作,因为它使用了一个称为闭包的概念。 关于这个概念,字面上有上千种解释,所以我在这里的解释会很简短。 如果您无法理解它,只需在谷歌搜索“JavaScript闭包”。

与许多其他语言不同的是,JavaScript具有函数作用域而不是块作用域。 因此,如果您在函数f中定义一个变量,并从f中返回另一个函数g,则g将可以从f中访问变量和参数。 为了演示目的:

function F () {
  var fVariable = 'Defined in F';
  return function G () {
    return fVariable; // <-- this is the closure
  }
}

var funcG = F(); // <-- execute F
funcG(); // -> 'Defined in F';

将这个简短的示例与您的第四个代码进行比较:它们几乎是相同的。 唯一的区别是,您的代码创建了一个额外的函数func

现在,如果调用Clicker.AddEventListener(“Click”,eventFunction(“It Works”)),则执行eventFunction,它返回另一个(匿名/lambda)函数,该函数通过闭包封装“It Works”字符串。 如果我们手写出来,这就是.addEventListener“看到”的内容:

clicker.addEventListener("click", function (event) {
  func("it works", event);
});

编辑:解决问题

下面是一个工作示例,请注意,我更改了函数名以反映它们的用途:

function eventHandlerFactory (myStr) { // <-- eventFunction in your code
  return function executeOnEvent (event) { // <-- executed if an event occurs
    console.log(myStr);
    console.log(event);
  }
}

clicker.addEventListener("click", eventHandlerFactory("it worked"));

EventHandlerFactory函数返回一个函数ExecuteOnEvent,该函数被传递到.AddEventListener中。 再手写出来,这就是翻译理解的:

clicker.addEventListener("click", function executeOnEvent (event) {
  console.log("it works");
  console.log(event);
});

匿名用户

我注意到的第一件事是这个eventFunction没有立即被调用

它将立即被调用。 但是,它返回一个新函数。 这是为click处理程序注册的函数。 此函数在调用时调用闭包中的函数func。 传递给这个函数的参数也保留在闭包中。

要理解这个概念,您需要理解闭包是如何工作的。 这是一个已经被广泛讨论过的主题,所以我将只向您指出JavaScript闭包是如何工作的?。