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

Viewed 272

I’ve found 2 ways of using callback functions in addEventListener and am confused about what each one does.

  • In the first option why don’t we use parenthesis? In the 2nd option we use it; what's the difference?

Both cartLogic and clearCart are part of same class. I did go through MDN but couldn't find clear answer.

Please clarify in detail.

Option 1:

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

Option 2:

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

Option One

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

Here the second argument which is the event handler passed to the addEventListener doesn't have parentheses because you're passing as argument a function which is already exists on the Object on which the cartLogic function is attached to. So when you are using this.clearCart you are refering to the object on which cartLogic function is attached to and which as also another method named clearCart.

Option Two

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

Here you are passing a anonymouse function define with arrow function expression.

Per definition the addEventListener expect as argument

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.

You can learn more about addEventListener on all arguyments which It take.

addEventListener expects a function as second argument (callback) for the event handler.

The first scenario you pass it a named function reference. This is like a variable representing the function object

If you did it like:

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

Then the function would get called immediately and would need to return another function that would get called when event occurs.


In the second scenario the callback function is an anonymous function that will get called when event occurs. When it gets called it calls the inner function

The differences will be in the first scenario your named function will have the event object as first argument and the context of this will be the element.

The context of this in second scenario will be your class, not the element, and if you want access to the event object you need to pass it in yourself

Simple example

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>

For clarity, your second example should be rewritten as:

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

Now if you erase everything from your examples except the differences, it will be very easy to understand how they're different.

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

The first example is the function, this.clearCart.

The second example is a function that executes the function, this.clearCart.

This second example involves needless indirection. That's the only difference. Instead of directly passing this.clearCart (as in the first example), you're passing a different function whose only purpose is to execute this.clearCart.

Option 1. -> Here we can't use parenthesis because it's a callback function's reference,if you will add parenthesis here,the function will be called immediately .

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

Option 2.-> here you are defining an anonymous function so it will work as callback and inside this the function this.clearCart(); will be called.

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

So to simplify your question you want to know what is the difference between using a function with and without parentheses.

Say we have a function logText() that looks something like this for example

function logText() {
  console.log("Hello world!")
}

Then we run the in the console like this

logText()

We get this sent back

"Hello world!"

Now when we do this in the console

logText

We get back a reference to the function that looks like this

ƒ logText() {
  console.log("Hello world!")
}

ƒ → function


What is the difference between this

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

And

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

The biggest difference between them both is the first example clearCart() is called immediately while the second example is wrapped in an anonymouse function and clearCart() is not being called immediately.


Does this change how things work?

Well not really, everything will still work the same way but why don't you have to add parathenese at the end of clearCart because this is refferencing the function so we can think of:

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

As

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

But this makes a difference in how we code when the the function (in this case addEventListener()) sends some value back to the callback in this case will most likey be the event (e) being sent back to the call back.

Lets assume your clearCart() has a param called 'e' or 'event' if we use your first example we do not have to decare e/event or parse the event ourselfs it will parsed for us but with your seconded example you would have to do something like this:

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

Why doesn't the second example not work without parentheses?

Because like I said early in the answer a function without parentheses is a reference to an function while a function with parentheses will be run.

We use functions without parentheses when we do not want to call the function instead we want to pass a reference of your function.

for example:

logText.length

This is parsing an reference of the function to the length method.

length used on a function will return the number of arguments expected by the function.


This is getting quite long so I'll end it here for now if there is something I didn't say or didn't say well leave a comment and I'll add it on :)

Also saw a comment on someone else's answer about the context of this and in my opinion that's not really related to this that's more about the difference between how you declare a function () => {} or function () {}.

Related