javascript - 在事件监听器中设置的参数化函数调用背后是否有有效的目的?

标签 javascript addeventlistener

在下面的代码片段中,我有 3 个按钮,其中有 3 个事件监听器链接到它们:

1) 第一个按钮有一个点击事件,调用函数doSomething,并且不发送任何参数。

2)第二个按钮有一个调用匿名函数的点击事件,匿名函数调用函数doSomethingElse,但同时发送一个参数。

3) 第三个按钮有一个单击事件,该事件调用函数doAnotherSomethingElse,并且还发送一个参数。

现在,我相信前两个示例是从事件监听器调用函数的正确方法:第一个不带参数,第二个在发送参数时。我认为第三个例子不是调用函数的正确方法,事实上,监听器不起作用。在此示例中,调用了该函数,但仅当在页面加载时执行事件代码时才调用该函数。未创建事件监听器,因此单击该按钮不会产生任何结果。

虽然我知道示例 3 不是使用事件监听器中的参数调用函数的正确方法,但我不明白为什么我在控制台中没有收到任何错误?我也不明白为什么函数实际上被成功调用(一次)并且参数被成功传递?看起来代码似乎是有效且正确的,并且确实有目的,但是我没有将它用于正确的目的,因为我不明白它的用途。

在事件监听器中设置的参数化函数调用背后是否有有效目的?代码没有产生错误是不是一个bug?或者是否有任何场景可以合法地将其用于某种目的?

var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var btn3 = document.getElementById("btn3");
var res1 = document.getElementById("result1");
var res2 = document.getElementById("result2");
var res3 = document.getElementById("result3");

function doSomething() {
  res1.innerHTML = res1.innerHTML + "Function doSomething called<br/>";
}

function doSomethingElse(parm) {
  res2.innerHTML = res2.innerHTML + "Function doSomethingElse called with parameter " + parm + "<br/>";
}

function doAnotherSomethingElse(parm) {
  res3.innerHTML = res3.innerHTML + "Function doAnotherSomethingElse called with parameter " + parm + "<br/>";
}

function start() {
  btn1.addEventListener("click", doSomething, false);
  //
  btn2.addEventListener("click", function() {
    doSomethingElse("foo");
  }, false);
  //
  btn3.addEventListener("click", doAnotherSomethingElse("bar"), false);
}

window.load = start();
button,
div {
  padding: 10px;
  margin: 10px;
}

#btn1, #result1 {
  background-color: lightblue;
}

#btn2, #result2 {
  background-color: coral;
}

#btn3, #result3 {
  background-color: lightgreen;
}
<button id="btn1">Button 1</button> <button id="btn2">Button 2</button> <button id="btn3">Button 3</button>

<div id="result1">
</div>

<div id="result2">
</div>

<div id="result3">
</div>

最佳答案

一个可能的目的是,如果您有一个函数返回另一个函数,有时称为柯里化(Currying):

const makeFn = param => () => console.log('invoking fn with param', param);
button.addEventListener('click', makeFn('foo'));
<button id="button">click</button>

或者,如果您不喜欢使用箭头函数(可以有隐式返回):

const makeFn = function(param) {
  return function() {
    console.log('invoking fn with param', param);
  };
};
button.addEventListener('click', makeFn('foo'));
<button id="button">click</button>

在这种情况下,在添加监听器时调用 makeFn 就可以了。

I don't understand why I then don't get any errors in the console?

因为不幸的是,addEventListener 并不要求它传递的参数是一个函数。相反,它只会默默地失败。

button.addEventListener('click', null);
<button id="button">click</button>

I also don't understand why the function is actually successfully called (once) and the parameter is successfully passed?

因为函数名后面的()会调用该函数。所以

btn3.addEventListener("click", doAnotherSomethingElse("bar"), false);

将使用参数bar调用doAnotherSomethingElse,更改res3.innerHTML,但因为doAnotherSomethingElse不会返回一个函数,不会设置事件监听器。

缓解此类问题的一种方法是使用类型检查器,如果您没有传递预期的参数,它会在您编写代码时向您发出警告。

另请注意,在您的代码片段中,

window.load = start();

导致与您描述的问题相同。当上述行运行时,您将立即调用 start,而不是告诉浏览器在加载窗口时运行 start。执行此操作的正确方法是

window.onload = start;

(不调用 start),就像使用命名函数附加监听器时所做的那样:

const fn = () => console.log('fn invoked');
const fn2 = () => console.log('fn 2 invoked');

document.addEventListener('click', fn);
document.onclick = fn2;

关于javascript - 在事件监听器中设置的参数化函数调用背后是否有有效的目的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57141460/

相关文章:

javascript - 在博客上的 mathjax 预览中显示新行

javascript - 用于提交事件的 addEventListener 尽早运行处理函数

javascript - jshint: 'use the function form of "使用严格的 "' and ' 文档未在简单的 javascript 文件中定义

javascript - 如何更改 HTML 文件中的文本

javascript - 使用事件监听器响应自定义下拉列表

javascript - 当事件监听器添加到另一个事件中时,获取事件源(带有附加监听器的节​​点)

javascript - 为什么我的 JavaScript 中的值是 'not an object'?

Javascript removeEventListener 不工作

javascript - Node JS - 如何从嵌套函数返回响应?

javascript - 在 div 中的 insideHTML 的每次更改中添加 EventListener