在下面的代码片段中,我有 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/