在 addEventListener 中使用回调的这两种方式有什么区别?

What's the difference between these 2 ways of using a callback in addEventListener?

提问人:vikramvi 提问时间:9/18/2020 最后编辑:GirkovArpavikramvi 更新时间:9/18/2020 访问量:380

问:

我找到了 2 种使用回调函数的方法,但对每种方法的作用感到困惑。addEventListener

  • 在第一种选择中,我们为什么不使用括号?在第二个选项中,我们使用它;有什么区别?

两者都是同一类的一部分。我确实经历了MDN,但找不到明确的答案。cartLogicclearCart

请详细澄清。

选项 1:

cartLogic() {
  clearCartBtn.addEventListener('click', this.clearCart);
}

选项 2:

cartLogic() {
  clearCartBtn.addEventListener('click', () => {
    this.clearCart();
  })
}
JavaScript 回调 addEventListener

评论

1赞 CertainPerformance 9/18/2020
另一个区别:事件参数
0赞 Jaromanda X 9/18/2020
我刚刚意识到 OP 只是在问......我应该删除我的教程评论:p()
0赞 vikramvi 9/18/2020
@JaromandaX我在调用方法/函数时感到困惑,什么时候可以省略( ),什么时候需要使用它?
0赞 Jaromanda X 9/18/2020
如果要执行该函数,请使用 ...否则。。。不要。。。在这种情况下,您不需要()

答:

-1赞 Dheeraj Joshi 9/18/2020 #1

选项 1.->这里我们不能使用括号,因为它是一个回调函数的引用,如果在这里加上括号,该函数会立即被调用。

cartLogic() {
clearCartBtn.addEventListener('click', this.clearCart);
}

选项 2.-> 在这里您定义了一个匿名函数,因此它将用作回调,并在其中调用该函数。this.clearCart();

  cartLogic() {
    clearCartBtn.addEventListener('click', () => {
        this.clearCart();
       })
   }

评论

0赞 charlietfl 9/18/2020
你没有提到一个显着的区别......调用时的上下文和事件参数this
0赞 Dheeraj Joshi 9/18/2020
@charlietfl,我以为他的查询只与括号有关
1赞 Yves Kipondo 9/18/2020 #2

选项一

cartLogic() {
    clearCartBtn.addEventListener('click', this.clearCart);
}

这里的第二个参数是传递给 的事件处理程序,没有括号,因为您传递的是一个函数作为参数,该函数已存在于该函数附加到的 Object 上。因此,当您使用时,您指的是函数附加到的对象以及另一个名为 .addEventListenercartLogicthis.clearCartcartLogicclearCart

选项二

cartLogic() {
    clearCartBtn.addEventListener('click', () => {
        this.clearCart();
    })
}

在这里,您传递了一个使用箭头函数表达式定义的匿名函数。

根据定义,addEventListener 期望作为参数

type:一个区分大小写的字符串,表示要侦听的事件类型。

听者发生指定类型的事件时接收通知的对象(实现 Event 接口的对象)。这必须是实现 EventListener 接口的对象或 JavaScript 函数。有关回调本身的详细信息,请参阅事件侦听器回调。

您可以在它需要的所有参数上了解有关 addEventListener 的更多信息。

评论

0赞 vikramvi 9/18/2020
感谢您提供信息,请进一步澄清;在选项 2 中,为什么在调用 this.clearCart ( ) 时不能省略 ( ),类似于我在选项 1 中所做的?我在调用方法/函数时感到困惑,什么时候可以省略( ),什么时候需要使用它?
0赞 Yves Kipondo 9/18/2020
在第二个选项中,您不能省略括号,因为您在定义匿名函数的同时将其作为参数传递
1赞 Mako 9/18/2020
如果要运行/执行函数,请在函数名称后使用括号。当事件发生时,侦听器中的回调会自动执行 - 因此 addEventListener 回调中不需要括号。在第一个示例中,“this.clearCart”用作回调本身,因此它会自动运行。在第二个示例中,匿名函数在执行其主体>执行,为了在该主体内运行函数,您需要括号,因此调用“this.clearCart()”
1赞 charlietfl 9/18/2020 #3

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>

0赞 GirkovArpa 9/18/2020 #4

为清楚起见,第二个示例应重写为:

cartLogic() {
  clearCartBtn.addEventListener('click', () => this.clearCart());
}

现在,如果您从示例中删除除差异之外的所有内容,则很容易理解它们的不同之处。

this.clearCart
() => this.clearCart()

第一个示例是函数 .this.clearCart

第二个示例是执行函数 的函数。this.clearCart

第二个例子涉及不必要的间接。这是唯一的区别。您不是直接传递(如第一个示例所示),而是传递一个不同的函数,其唯一目的是执行 。this.clearCartthis.clearCart

-1赞 Fletcher Rippon 9/18/2020 #5

因此,为了简化您的问题,您想知道使用带括号和不带括号的函数有什么区别。

例如,假设我们有一个看起来像这样的函数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()eevent

cartLogic() {
    clearCartBtn.addEventListener('click', e => { 
        this.clearCart(e) 
    });
}

为什么第二个示例没有括号就不起作用?

因为就像我在答案前面说的,不带括号的函数是对函数的引用,而带括号的函数将运行。

当我们不想调用函数时,我们使用不带括号的函数,而是想要传递函数的引用。

例如:

logText.length

这是解析函数对方法的引用。length

length在函数上使用将返回函数预期的参数数。


这已经很长了,所以我现在就在这里结束,如果有什么我没有说或没有说好的话,请发表评论,我会把它添加到:)

还看到了对其他人关于上下文的回答的评论,在我看来,这与此无关,这更多的是关于您如何声明函数或 .this() => {}function () {}