提问人:vikramvi 提问时间:9/18/2020 最后编辑:GirkovArpavikramvi 更新时间:9/18/2020 访问量:380
在 addEventListener 中使用回调的这两种方式有什么区别?
What's the difference between these 2 ways of using a callback in addEventListener?
问:
我找到了 2 种使用回调函数的方法,但对每种方法的作用感到困惑。addEventListener
- 在第一种选择中,我们为什么不使用括号?在第二个选项中,我们使用它;有什么区别?
两者都是同一类的一部分。我确实经历了MDN,但找不到明确的答案。cartLogic
clearCart
请详细澄清。
选项 1:
cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}
选项 2:
cartLogic() {
clearCartBtn.addEventListener('click', () => {
this.clearCart();
})
}
答:
选项 1.->这里我们不能使用括号,因为它是一个回调函数的引用,如果在这里加上括号,该函数会立即被调用。
cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}
选项 2.-> 在这里您定义了一个匿名函数,因此它将用作回调,并在其中调用该函数。this.clearCart();
cartLogic() {
clearCartBtn.addEventListener('click', () => {
this.clearCart();
})
}
评论
this
选项一
cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}
这里的第二个参数是传递给 的事件处理程序,没有括号,因为您传递的是一个函数作为参数,该函数已存在于该函数附加到的 Object 上。因此,当您使用时,您指的是函数附加到的对象以及另一个名为 .addEventListener
cartLogic
this.clearCart
cartLogic
clearCart
选项二
cartLogic() {
clearCartBtn.addEventListener('click', () => {
this.clearCart();
})
}
在这里,您传递了一个使用箭头函数表达式定义的匿名函数。
根据定义,addEventListener 期望作为参数
type:一个区分大小写的字符串,表示要侦听的事件类型。
听者发生指定类型的事件时接收通知的对象(实现 Event 接口的对象)。这必须是实现 EventListener 接口的对象或 JavaScript 函数。有关回调本身的详细信息,请参阅事件侦听器回调。
您可以在它需要的所有参数上了解有关 addEventListener 的更多信息。
评论
addEventListener 需要一个函数作为事件处理程序的第二个参数(回调)。
第一种方案是向其传递命名函数引用。这就像一个表示函数对象的变量
如果你这样做,就像:
addEventListener('click', myFunc()) // with ()
然后,该函数将立即被调用,并且需要返回另一个函数,该函数将在事件发生时被调用。
在第二种情况下,回调函数是一个匿名函数,将在事件发生时调用该函数。当它被调用时,它会调用内部函数
区别在于,在第一种情况下,命名函数将事件对象作为第一个参数,而 的上下文将是元素。this
在第二种情况下,上下文将是你的类,而不是元素,如果你想访问事件对象,你需要自己传递它this
简单示例
document.getElementById('1').addEventListener('click', myFunc)
document.getElementById('2').addEventListener('click', (evt)=> myFunc(evt))
document.getElementById('3').addEventListener('click', ()=> myFunc())
function myFunc(event){
console.clear()
if(event){
console.log('Type of event:', event.type);
}else{
console.log('No event object')
}
if(this instanceof HTMLElement){
console.log('"this" is element:', this.tagName)
}else{
console.log('"this" is your class')
}
}
<button id="1">Named function</button>
<button id="2">Anonymous with evt</button>
<button id="3">Anonymous no evt</button>
为清楚起见,第二个示例应重写为:
cartLogic() {
clearCartBtn.addEventListener('click', () => this.clearCart());
}
现在,如果您从示例中删除除差异之外的所有内容,则很容易理解它们的不同之处。
this.clearCart
() => this.clearCart()
第一个示例是函数 .this.clearCart
第二个示例是执行函数 的函数。this.clearCart
第二个例子涉及不必要的间接。这是唯一的区别。您不是直接传递(如第一个示例所示),而是传递一个不同的函数,其唯一目的是执行 。this.clearCart
this.clearCart
因此,为了简化您的问题,您想知道使用带括号和不带括号的函数有什么区别。
例如,假设我们有一个看起来像这样的函数logText()
function logText() {
console.log("Hello world!")
}
然后我们在控制台中运行,如下所示
logText()
我们把这个发回去
"Hello world!"
现在,当我们在控制台中执行此操作时
logText
我们得到一个对函数的引用,如下所示
ƒ logText() {
console.log("Hello world!")
}
ƒ →功能
这有什么区别
cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}
和
cartLogic() {
clearCartBtn.addEventListener('click', () => {
this.clearCart()
});
}
它们之间最大的区别是,第一个示例是立即调用的,而第二个示例是包装在匿名函数中,而不是立即调用。clearCart()
clearCart()
这会改变事情的运作方式吗?
好吧,不是真的,一切仍然以相同的方式工作,但是为什么您不必在末尾添加 parathenese,因为这是引用函数,因此我们可以想到:clearCart
cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}
如
cartLogic() {
clearCartBtn.addEventListener('click', () => {
// All code for your function
...
});
}
但是,当函数(在本例中)将一些值发送回调时,这会影响我们的编码方式,在这种情况下,最有可能的是事件 (e) 被发送回回回调。addEventListener()
假设你有一个名为“e”或“event”的参数
如果我们使用您的第一个示例,我们不必自行解析/或解析事件,但是对于您的第二个示例,您将不得不执行以下操作:clearCart()
e
event
cartLogic() {
clearCartBtn.addEventListener('click', e => {
this.clearCart(e)
});
}
为什么第二个示例没有括号就不起作用?
因为就像我在答案前面说的,不带括号的函数是对函数的引用,而带括号的函数将运行。
当我们不想调用函数时,我们使用不带括号的函数,而是想要传递函数的引用。
例如:
logText.length
这是解析函数对方法的引用。length
length
在函数上使用将返回函数预期的参数数。
这已经很长了,所以我现在就在这里结束,如果有什么我没有说或没有说好的话,请发表评论,我会把它添加到:)
还看到了对其他人关于上下文的回答的评论,在我看来,这与此无关,这更多的是关于您如何声明函数或 .this
() => {}
function () {}
评论
()
()