带参数的事件监听器

Par*_*i I 0 javascript dom-events

我想将参数传递给 Javascript 中的事件侦听器。我找到了解决方案,但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用。

我有 C/C++ 背景,但是 Javascript 函数的执行有很大不同。您能否帮助我理解以下示例如何以及为何有效或无效?

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

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

function eventFunction()
{
  console.log("works");
}
Run Code Online (Sandbox Code Playgroud)

如果我在 eventListener 上包含括号,该函数将在没有事件触发的情况下执行一次,然后不执行任何操作:

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

function eventFunction()
{
  console.log("works");
}
Run Code Online (Sandbox Code Playgroud)

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


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

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

function eventFunction(myStr)
{
    console.log(myStr);
}
Run Code Online (Sandbox Code Playgroud)

它在不触发事件的情况下调用 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) 
  };
}
Run Code Online (Sandbox Code Playgroud)

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

但是,我不知道如何在每个函数中传递参数。我知道“works”文字被传递给 eventFunction 上的 myStr。但是,在函数 func 中,还有一个未由 eventFunction 传递的附加事件参数。

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

另请注意,我想将参数传递给没有全局作用域的 eventFunction,否则就不需要传递参数。

Dav*_*vid 6

让我们一步一步地剖析这一点。

一般信息

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

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

实施例1

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

实施例2

在此示例中,您将 aString和传递undefined.addEventListener,这不是.addEventListener预期的结果。你可能会问自己“我什么时候进来的undefined ”。好吧,当你通过在后面添加括号来执行 你的命令时,它就会发生。这里,JS 的语法与大多数其他语言的语法相同,在函数右侧添加括号来执行该函数。eventFunction()

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

clicker.addEventListener("click", undefined)
Run Code Online (Sandbox Code Playgroud)

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

实施例3

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

实施例4

最后一个示例中的代码可以工作,因为它使用了一个称为闭包的概念。这个概念实际上有数千种解释,所以我在这里的解释非常简短。如果你无法理解它,只需谷歌搜索“javascriptclosures”。

与许多其他语言相比,JavaScript 采用函数作用域而不是块作用域。因此,如果您在函数内部定义变量FG从内部返回另一个函数F,则可以从内部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';
Run Code Online (Sandbox Code Playgroud)

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

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

clicker.addEventListener("click", function (event) {
  func("it works", event);
});
Run Code Online (Sandbox Code Playgroud)

编辑:解决问题

这是一个工作示例,请注意,我更改了函数名称以反映其用途:

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"));
Run Code Online (Sandbox Code Playgroud)

eventHandlerFactory函数返回一个函数executeOnEvent,该函数被传递到.addEventListener。再用手写出来,解释器是这样理解的:

clicker.addEventListener("click", function executeOnEvent (event) {
  console.log("it works");
  console.log(event);
});
Run Code Online (Sandbox Code Playgroud)