this is an important keyword in Object Oriented Programming. Unfortunately, the value of this changes depending on its surrounding context, which confuses the heck out of people.
I want to show you the different values this will be in different contexts, so you don’t get confused.
Six different contexts
The value of this changes depending on its context. There are six different contexts:
this when used globally
this in a simple function
this in a constructor
this in an instance
this in a method
this in an arrow function
When this is used globally
this is Window if you used it globally.
console.log(this)
When this is used in a simple function
this is always Window if you use it in a simple function.
When I say simple function, I mean:
Functions that are declared with the function keyword
Functions that are NOT methods of an object
function sayThis () {
console.log(this)
}
When this is used in a constructor
When this is used in a constructor, it refers to the instance that will be created.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
console.log(this)
}
Constructors look like simple functions, which can be a source of confusion.
When you create instances from constructors, you must use the new keyword. If you use the new keyword, this will refer to the instance.
// DO THIS
const zell = new Human('Zell', 'Liew')
If you don’t use the new keyword, you will call the constructor like a simple function. When you call the constructor like a simple function, this refers to Window. Properties you declared with this will be added as global variables.
// DON'T DO THIS
const zell = Human('Zell', 'Liew')
The same thing applies to this in a class’s constructor function.
class Human {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
console.log(this)
}
}
When this is used in an instance
When this is used in an instance, it refers to the instance.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
console.log(this)
}
const zell = new Human('Zell', 'Liew')
When this is used in a method
When this is used in a method, this refers to the object that calls the method.
When this is used in an arrow function, this will be the this value in the surrounding lexical scope.
Arrow functions change MANY things, so there are two best practices you need to know.
Best Practice #1: Don’t use arrow functions to create methods
When you use Object Oriented Programming, you may need to call a method from another method. If you want to do this, you need this to point back to the instance (which called the method).
Example:
Let’s build a Human with a sayHi method. sayHi says Hi!, then proceeds to end the conversation by saying the person’s name.
We can use a getFullName method that returns the full name of the person inside sayHi.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Human.prototype.getFullName = function () {
return this.firstName + ' ' + this.lastName
}
Human.prototype.sayHi = function () {
console.log(`Hi! My name is ${this.getFullName()}`)
}
An instance can use the sayHi method and you’d expect it to work. It works because this points back to the instance.
const zell = new Human('Zell', 'Liew')
zell.sayHi()
Watch what happens if you change sayHi to an arrow function.
Human.prototype.sayHi = _ => {
console.log(`Hi! My name is ${this.getFullName()}`)
}
// ...
zell.sayHi()
…
Why?
In this case, this inside sayHi points to Window. Since Window doesn’t have a getFullName method, calling getFullName will result in an error.
this points to Window because Window is the lexical this value. We can verify that this is Window by logging it.
Human.prototype.sayHi = _ => {
console.log(this)
console.log(`Hi! My name is ${this.getFullName()}`)
}
// ...
zell.sayHi()
In short: Do not use arrow functions to create methods!
Best Practice #2: Use arrow functions to create functions INSIDE methods
this always points to Window when it is used in a simple function. The statement is true even if you create a simple function inside a method.
const object = {
this () {
function sayThis () {
console.log(this)
}
sayThis()
}
}
object.this()
We usually want this to be the object when we use this inside a method. (So we can call other methods).
One way is to assign this to another variable. We often call this variable self or that. We’ll then use self or that inside the function.
const object = {
this () {
const self = this
function sayThis () {
console.log(self)
}
sayThis()
}
}
object.this()
Another way is to create a new function with bind.
If you use arrow functions, you don’t need to use self, that, or bind. You can write the arrow function directly, and this will point to the object (because the surrounding this value is the object).