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

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

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

cartLogicclearCart 都是 class 的一部分。我确实通过了 MDN,但找不到明确的答案。

请详细说明。

选项 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();
       })
   }

选项一

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

这里的第二个参数是传递给 addEventListener 的事件处理程序,它没有括号,因为您作为参数传递的函数已经存在于 [=13= 所在的对象上] 函数附加到。因此,当您使用 this.clearCart 时,您指的是附加了 cartLogic 函数的对象,以及另一个名为 clearCart.

的方法

选项二

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

这里你传递了一个用 arrow function expression 定义的匿名函数。

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

type: A case-sensitive string representing the event type to listen for.

listener The object that receives a notification (an object that implements the Event interface) when an event of the specified type occurs. This must be an object implementing the EventListener interface, or a JavaScript function. See The event listener callback for details on the callback itself.

您可以了解有关 addEventListener 的所有论点的更多信息。

addEventListener 需要一个函数作为事件处理程序的第二个参数(回调)。

第一个场景你传递给它一个命名函数引用。这就像代表函数对象的变量

如果你这样做:

addEventListener('click', myFunc()) // with ()

然后该函数将立即被调用,并且需要 return 另一个在事件发生时被调用的函数。


在第二种情况下,回调函数是一个匿名函数,它将在事件发生时被调用。当它被调用时,它会调用内部函数

区别在于第一种情况,您的命名函数将事件对象作为第一个参数,this 的上下文将是元素。

第二种情况下 this 的上下文将是你的 class,而不是元素,如果你想访问事件对象,你需要自己传递它

简单示例

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() 没有被立即调用。


这会改变事情的运作方式吗?

不是真的,一切仍然会以相同的方式工作,但为什么你不必在 clearCart 的末尾添加 parathenese 因为这是引用函数所以我们可以想到:

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

作为

cartLogic() {
    clearCartBtn.addEventListener('click', () => {
        // All code for your function 
        ...
    });
}

但是当函数(在本例中 addEventListener())将一些值发送回回调时,这对我们的编码方式产生了影响,在这种情况下,很可能是事件 (e) 被发送回回电。

假设您的 clearCart() 有一个名为 'e' 或 'event' 的参数 如果我们使用您的第一个示例,我们不必取消 e/event 或自己解析事件,它将为我们解析,但是对于您的第二个示例,您必须执行以下操作:

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

为什么第二个例子没有括号就不能工作?

因为就像我在回答的前面所说的那样,不带括号的函数是对函数的引用,而带括号的函数将是 运行.

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

例如:

logText.length

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

length 用于函数将 return 函数期望的参数数量。


这篇文章很长,所以我会在这里结束如果有什么我没有说或没有说好的留下评论,我会添加它:)

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