This in JavaScript

Are you confused by the this keyword in JavaScript? It confuses everyone in the beginning, so don’t worry about it. You’re not alone.

But that doesn’t mean you can go on without understanding this forever. It is used so much in JavaScript and in tutorials everywhere that you need to grasp what this is sooner or later. Once you understand this, you’ll realize that it’s much simpler than you think it is.

By the end of this article, you would have demystified this for yourself. You’ll know what it is, what it does and how to use it.

So, what is this?

this is a keyword whose value changes depending on how a function gets called. There six different ways where this can take on new values. They are:

  1. this in global context
  2. this in object construction
  3. this in an object method
  4. this in a simple function
  5. this in an arrow function
  6. this in an event listener

You may wonder what this is in each context and why there’s a need to change this in the first place. To answer your question, let look at how this changes in each of the six contexts.

This in a global context

When this is called outside of any function, in a global context, this defaults to the Window object in the browser.

console.log(this) // Window
This defaults to window object in browsers
This defaults to window object in browsers

Usually, you wouldn’t use this in a global context anyway, so the value of this here doesn’t really matter. Let’s move on to the next context.

This in object construction

When you create a new instance of an object with the new keyword, this refers to the instance.

function Human (age) {
  this.age = age
}

let greg = new Human(22)
let thomas = new Human(24)

console.log(greg) // this.age = 22
console.log(thomas) // this.age = 24
This refers to the instance
This refers to the instance

You can see that greg is an instance of Human in the code above. Now, whenever you reference greg, you won’t accidentally get thomas. So, setting this to be the instance makes perfect sense.

Let’s look at a closely related context next – this in an object method.

This in an object method

Methods are fancy words for functions that are associated with an object, like this:

(Note: Methods here are defined with the ES6 object literal shorthand. Check out this article if you’re unsure what it does).

let o = {
  // A method
  aMethod () {}
}

this within any method refers to the object itself.

let o = {
  sayThis () {
    console.log(this)
  }
}

o.sayThis() // o
this in a method refers to the object itself
this refers to the object

Since this refers to the object, you can use methods to get the instance of an object, like this:

function Human (name) {
  return {
    name,
    getName() {
      return this.name
    }
  }
}

const zell = new Human('Zell')
const vincy = new Human('Vincy')

console.log(zell.getName()) // Zell

In these two object contexts, you can see that the changed value of this lets you get the right instance, which is the basis for Object-oriented programming. That’s a topic for another day though.

Let’s move on to the next context.

This in a simple function

Simple functions are functions you know extremely well; like the one below. Anonymous functions written in the same form are also considered simple functions.

function hello () {
  // say hello!
}

On browsers, this is always set to Window in a simple function. The same is true even if you call a simple function in an object method.

function simpleFunction () {
  console.log(this)
}

const o = {
  sayThis () {
    simpleFunction()
  }
}

simpleFunction() // Window
o.sayThis() // Window

Unfortunately, the change in this is unexpected for beginners. They expect this to remain the same within object methods. I got caught in it too.

To see why, consider the following code. Here, a this.speakLeet function is executed later within a setTimeout function.

const o = {
  doSomethingLater () {
    setTimeout(function() {
      this.speakLeet() // Error
    }, 1000)
  },
  speakLeet() {
    console.log(`1337 15 4W350M3`)
  }
}

Unfortunately, the code above results in an error. The error occurs because this is set to Window in the setTimeout function. Window does not have a speakLeet method.

One quick fix is to create a variable that stores the reference to the this. This variable is often called self or that.

const o = {
  doSomethingLater () {
    const self = this
    setTimeout(function() {
      self.speakLeet()
    }, 1000)
  },
  speakLeet() {
    console.log(`1337 15 4W350M3`)
  }
}

A second way to fix this problem is to use the new ES6 arrow functions, which brings us to the next context.

This in arrow functions

this in an arrow function is always the same as this around it (in its immediate scope). So, if you use arrow functions within an object method, the this context stays as the object, not Window.

With arrow functions, the speakLeet example could be written in the following way:

const o = {
  doSomethingLater () {
    setTimeout(() => this.speakLeet(), 1000)
  },
  speakLeet() {
    console.log(`1337 15 4W350M3`)
  }
}

(For more info on arrow functions, read this article)

A third way to change the value of this within any function is to use either bind, call or apply. We’ll look at bind later in the article, and call and apply another time. But first, let’s go through the final context — event listeners.

This in event listeners

this is set to the element that fired the event in an event listener:

let button = document.querySelector('button')

button.addEventListener('click', function() {
  console.log(this) // button
})

When creating more complex components, you may find yourself creating event listeners within methods.

function LeetSpeaker (elem) {
  return {
    listenClick () {
      elem.addEventListener('click', function () {
        // Do something here
      })
    }
  }
}

Since this refers to the element in the event listener, if you need to activate another method, you need to provide a reference to the object with.

function LeetSpeaker (elem) {
  return {
    listenClick () {
      const self = this
      elem.addEventListener('click', function () {
        self.speakLeet()
      })
    },
    speakLeet() { console.log(`1337 15 4W350M3`) }
  }
}

Alternatively, you can use an arrow function. If you do so, you can still get the element with event.currentTarget.

function LeetSpeaker (elem) {
  return {
    listenClick () {
      elem.addEventListener('click', (e) => {
        console.log(e.currentTarget) // elem
        this.speakLeet()
      })
    },
    speakLeet() { console.log(`1337 15 4W350M3`) }
  }
}

But both methods aren’t good enough to help you remove event listeners when the need arises, both are anonymous functions.

To remove an event listener, the callback passed as the second value needs to be a named function:

function someFunction () {
  console.log('do something')

  // Removes the event listener.
  document.removeEventListener('click', someFunction)
}

document.addEventListener('click', someFunction)

(Here’s more on callbacks if you need help with them).

If you need this to reference the object in an event listener, you need to use bind to manually create a this context.

function LeetSpeaker (elem) {
  return {
    listenClick () {
      this.listener = this.speakLeet.bind(this)
      elem.addEventListener('click', this.listener)
    },

    speakLeet(e) {
      const elem = e.currentTarget
      console.log(`1337 15 4W350M3`)
      elem.removeEventListener('click', this.listener)
    }
  }
}

The code above may confuse you if you’ve don’t understand bind. So, before I show you what is happening, let’s take a detour and understand what bind does.

Changing this with bind

bind is a method that is present in every function. It allows you to change the this context. This method takes in any number of arguments and returns the bound function.

const sayThis = _ => console.log(this)
const boundFunc = sayThis.bind(/* arguments...*/)

The first parameter you pass into bind becomes this in the bound function. Once you have created a bound function, you can call it anytime you wish:

const sayThis = _ => console.log(this)
const boundFunc = sayThis.bind({hippy: 'hipster'})
boundFunc()
Bind helps to change this
Bind helps to change this

The other parameters you pass to bind will be passed as arguments to the original function

const sayParams = (...args) => console.log(...args)
const boundFunc = sayParams.bind(null, 1, 2, 3, 4, 5)
boundFunc()
Other params passed to bind become arguments in the function
Other params passed to bind become arguments in the function

That’s really all you need to know about bind.

Now, let’s look back at the code to remove event listeners and dissect what is happening:

function LeetSpeaker (elem) {
  return {
    listenClick () {
      // Binds this.speakLeet with a reference to the instance.
      // Sets bound function to this.listener, so we can remove it later.
      this.listener = this.speakLeet.bind(this)
      elem.addEventListener('click', this.listener)
    },

    speakLeet(e) {
      console.log(`1337 15 4W350M3`)

      // Gets the element so we can remove the event listener.
      const elem = e.currentTarget

      // Removes the event listener.
      elem.removeEventListener('click', this.listener)
    }
  }
}

Here’s a Codepen for you to see the code in action.

See the Pen SpeakLeetOnce? by Zell Liew (@zellwk) on CodePen.

And that’s all you need to know about this.

Let’s wrap up.

Wrapping up

this is a crucial keyword in JavaScript. It appears in many JavaScript frameworks, so you have to know what it does.

In this article, you learned about the six different contexts where this takes on different values. You also learned how to change the this context with functions like bind. Additionally, you also learned to remove event listeners properly.

That’s all you need to know about this. Just master the concepts taught in this article and you won’t ever get confused anymore.

If you have any questions, just hit me up in the comments below :)

(If you liked this article, I'd appreciate it if you could share it. 🤗)

Hold on while i sign you up…

🤗
Woohoo! You’re in!
Now, hold on while I redirect you.