TIL – addEventListener accepts functions and (!) objects
Tags: javascript
Published: 2020-12-06 19:01:50

---
title: TIL – addEventListener accepts functions and (!) objects
published: true
description: addEventListener accepts callback functions but also elements that implement the EventListener interface
tags: javascript
canonical_url: https://www.stefanjudis.com/today-i-learned/addeventlistener-accepts-functions-and-objects/
---

To build interactive web interfaces, you have to use DOM ([Document Object Model](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)) events. How does that usually work? 

You define the event type you're interested in, pair it with a callback function and you are ready to react to clicks, keypresses, scrolls and many other events.

For example, to react to a button click, the following code can be used:

```javascript
document.querySelector('button')
  .addEventListener('click', () => {
    console.log('element clicked');
  });
```

The code queries the DOM, grabs a specific element and adds a `click` event listener to it using `addEventListener`. 

[According to MDN, `target.addEventListener` defines the following parameters](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener):

```
target.addEventListener(type, listener [, options]);
target.addEventListener(type, listener [, useCapture]);
target.addEventListener(type, listener [, useCapture, wantsUntrusted  ]); // Gecko/Mozilla only
```

`addEventListener` accepts the event type, a `listener` callback function and an `options` or `useCapture` parameter. 

([To learn more about possible `options` or `useCapture` head over to the MDN `addEventListener` documentation.](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener))

**What if I told you, that the `listener` parameter can be a function but also an object?** 

## `addEventListener` and the `EventListener` interface

It turns out that MDN defines `listener` as the following: 

> [listener] must be an object implementing the EventListener interface, or a JavaScript function.

[The early DOM events specification](https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener) (we're talking pre-HTML5 here) defined an `EventListener` interface. Objects implementing the interface (they had to define a `handleEvent` method) where valid to be passed to the `addEventListener` method.

```javascript
// a class implementing
// the `EventListener` interface
class EventHandler {
  constructor() {
    this.eventCount = 0;
  }

  handleEvent() {
    this.eventCount++;
    console.log(`Event triggered ${this.eventCount} time(s)`);
  }
}

document.querySelector('button')
  .addEventListener('click', new EventHandler());
```

The code above uses a JavaScript class `EventHandler`. Initialized event handler objects can be passed to `addEventHandler` and they keep track of the number of times a specific event occurred ([check it on CodePen](https://codepen.io/stefanjudis/pen/rNMeqMv)). All information is stored in the object itself, and the code works without any out of scope variables. I like this pattern and I can see it come in handy when dealing with sequential events.

According to MDN, the `EventListener` interface is supported by all major browsers and you can safely pass objects implementing it to `addEventListener`. 

When would you pass `EventListener` objects to `addEventListener`? I'd love to learn about more examples!