【问题标题】:Event listeners with arguments带参数的事件监听器
【发布时间】:2019-05-23 12:42:25
【问题描述】:

我想将参数传递给 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 没有立即调用。 这是为什么呢?

但是,我不知道如何在每个函数中传递参数。 我知道“作品”文字在 eventFunction 上传递给 myStr。 但是在函数 func 中有一个额外的事件参数不是由 eventFunction 传递的。

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

另外请注意,我要向 eventFunction 传递不具有全局范围的参数,否则不需要传递参数。

【问题讨论】:

标签: javascript dom-events


【解决方案1】:

让我们一步一步来剖析。

一般信息

.addEventListener 函数/方法接受 2(或 3)个参数:

  • String,其值为事件类型/名称(例如 "click"
  • 指向Function 的指针,应在事件发生时执行
  • Boolean,指定是否应使用事件冒泡或事件传播。此参数是可选的,可以省略。

示例 1

在您的第一个示例中,您将 String ("click") 和 指向 Function (eventFunction) 的指针传递给 .addEventListener。一切都按预期工作,事件发生并执行函数。

示例 2

在此示例中,您将Stringundefined 传递给.addEventListener,这不是.addEventListener 所期望的。你可能会问自己“我什么时候传入undefined”。好吧,它发生在你执行你的eventFunction 之后添加parens ()。在这里,JS 中的语法与大多数其他语言中的语法相同,在函数的右侧添加括号即可执行该函数。

因为您的eventFunction 没有明确返回任何内容,所以它会自动返回undefined。因此,这就是.addEventListener 得到的:

clicker.addEventListener("click", undefined)

但是,因为您执行了eventFunction,它会将"It worked" 记录到控制台一次

示例 3

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

示例 4

最后一个示例中的代码有效,因为它使用了一个称为闭包的概念。字面上对这个概念有数千种解释,所以我在这里的解释会很短。如果你理解它有困难,只是谷歌 “javascript 闭包”。

与许多其他语言相比,JavaScript 具有 函数作用域 而不是 块作用域。因此,如果您在函数F 中定义一个变量并从F 中返回另一个函数GG 将可以访问来自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);
});

【讨论】:

  • 感谢您非常详细的解释。因此,在函数 eventFunc 中,我们返回一个指向匿名函数的指针,该函数接受一个参数(事件)并执行由于闭包而可以访问 myStr 字符串的 func 函数。按照您的逻辑,我认为如果我直接返回指向 func 的指针而不是指向调用 func 的未定义函数的指针,它可能会起作用。所以我尝试了function eventFunction(myStr) { function func(event,myStr) {console.log(myStr);} return func(event,myStr); }
  • Continuing.. 我现在得到的输出是事件对象,好像函数 func 包含 console.log (event) 为什么会这样?
  • ..继续。经过一番思考,我认为这与指向事件监听器期望的函数的指针类型有关。难道它只需要一个参数函数指针,并且该参数始终是事件,所以它也使我的第二个参数事件????!
  • @ParakmiI (1) 更新了我的答案以包含一个工作示例。 (2)关于你的最后一个问题:事件处理函数(见上面更新的代码)总是隐式地接收 Event 对象。是的,.addEventListener 函数需要一个元数为 1 的函数。这就是我们使用闭包的原因(尽管还有其他方法可以做到这一点,例如 部分应用程序)。
【解决方案2】:

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

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

要理解这个概念,您需要了解闭包的工作原理。这是一个已经被广泛讨论的话题,所以我只是将您指向How do JavaScript closures work?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多