A JavaScript interview question asked at Google
Tags: career, javascript, codenewbie
Published: 2020-01-29 20:40:15

Hello and welcome back to Code Review, a series of coding interview challenges and career related content released weekly exclusively on Dev.to. I’m Elisabeth and I’ve been a software engineer for about 4+ years now. I’m passionate about sharing my knowledge, and best tips and tricks when it comes to acing that interview and or just leveling up your coding skills. If you want more content and challenges like these, subscribe to the [Coderbyte newsletter here](https://coderbyte.typeform.com/to/fb7Yk8). That’s it for stand up - let’s get to challenge solving!

## The Challenge

Write a class, `EventEmitter` that has three methods: `on`, `emit`, and `removeListener`.
* `on("eventName", callbackFn)` - a function that takes an `eventName` and a `callbackFn`, should save the callbackFn to be called when the event with `eventName` is emitted.
* `emit("eventName", data)` - a function that takes an `eventName` and `data` object, should call the `callbackFn`s associated with that event and pass them the `data` object.
* `removeListener("eventName", callbackFn)` - a function that takes `eventName` and `callbackFn`, should remove that `callbackFn` from the event.

For example:

```javascript

let superbowl = new EventEmitter()

const cheer = function (eventData) {
  console.log('RAAAAAHHHH!!!! Go ' + eventData.scoringTeam)
}

const jeer = function (eventData) {
  console.log('BOOOOOO ' + eventData.scoringTeam)
}

superbowl.on('touchdown', cheer)
superbowl.on('touchdown', jeer)

superbowl.emit('touchdown', { scoringTeam: 'Patriots' }) // Both cheer and jeer should have been called with data

superbowl.removeListener('touchdown', jeer)

superbowl.emit('touchdown', { scoringTeam: 'Seahawks' }); // Only cheer should have been called

```

## The solution:

This is a great opportunity to use ES6 classes. In case you haven’t used them before, check out their syntax [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). We can start with a basic structure for the class `EventEmitter` and initialize it with an object `events` that we will use to track our events.

```javascript
class EventEmitter {
  constructor () {
    this.events = {}
  }
}
```

### On

Next we can start working on our methods. First up is `on`. Here is the code for that:

```javascript
on (eventName, callbackFn) {
  if (!this.events[eventName])  {
    this.events[eventName] = []
  }
  this.events[eventName].push(callbackFn)
}
```

Because functions are *first class objects* in javascript, which basically means they can be stored in a variable, an object, or an array, we can just push the callback function to an array stored at the key `eventName` in our events object.

### Emit

Now, for our `emit` function. 

```javascript
  emit (eventName, eventData) {
    if (!this.events[eventName]) return
    this.events[eventName].forEach(fn => fn(eventData))  
  }
```

This solution takes advantage of what is called *closure* in javascript. If you are coding in Javascript in your interview, understanding closure can be vital. A closure is essentially when a function has references to its surrounding state or its lexical environment. You can also think of this as a closure allowing you access to an outer function’s scope from inside an inner function. Using global variables is a great simple example of closure. 

Here’s another great example of using closure to track how many times a function was called.

```javascript
function tracker (fn) {
  let numTimesCalled = 0
  return function () {
    numTimesCalled++
    console.log('I was called', numTimesCalled)
    return fn()
  }
}

function hello () {
  console.log('hello')
}

const trackedHello = tracker(hello)
```

The inner function returned in `tracker` closes over the variable numTimesCalled and maintains a reference to it for the life of the `trackedHello` function. Cool stuff huh??

### RemoveListener

The `removeListener` method is probably the easiest of the three. Here is a solution - 

```javascript
removeListener (eventName, callbackFn) {
  const idx = this.events[eventName].indexOf(callbackFn)
  if (idx === -1) return
  this.events[eventName].splice(idx, 1)
}
```


And that’s the class! Pun intended :) Seeing if you can implement methods that are part of the language is a great way to practice for interviews. See you all next week!