What is this
and why is it so confusing to understand? Simply put, this
keyword refers to the object that is executing the current function (the "owner" of the function). Well ok, now in plain English?
Let's just say that this
is dependent on the context in which is used. If we find it in a regular function (we make a simple function call), it references the global object (called window in browsers and global in Node) and if we find it inside a method (a function inside an object), it will reference that object.
For a better understanding, I recommend you try the code below in the console. Note that I'm using the syntax prior to ES6 for writing functions.
function printKeyword() {
console.log(this);
}
printKeyword(); // prints the window object
const someObject = {
someProp: 'random',
someFunction() {console.log(this)}
}
console.log(someObject.someProp) // prints random
someObject.someFunction(); // prints {someProp: "random", someFunction: ƒ}
In the first example, printKeyword
it's not a method on an object so, as expected it will print the window object to the console. In the second example, someFunction
is a method on someObject
, so when trying to log this
we'll print the object itself.
If we put it this way, it's not too complicated, right? So why all the fuss? Of course, these are very simple examples so let's take it up a notch.
const myDoggo = {
name: 'Lulu',
age: 3,
hobbies: ['sleeping', 'TV', 'swimming'],
printName() {
console.log(this.name)
},
printAge() {
console.log(this.age)
},
printHobbies() {
console.log(this.hobbies)
},
printAgeAndHobbies() {
this.hobbies.forEach(function(hobby) {console.log(hobby + this.age)})
}
}
myDoggo.printName() // prints Lulu
myDoggo.printAge() // prints 3
myDoggo.printHobbies() // prints ["sleeping", "TV", "swimming"]
myDoggo.printAgeAndHobbies() // prints sleepingundefined TVundefined swimmingundefined
We have an object with two properties and four methods. You might notice that the first three methods seem to work perfectly fine but when we get to printAgeAndHobbies
we might have a surprise. Trying to log hobby + this.age
prints the hobby but not the age. Actually we get undefined
.
This is because this.hobbies
is inside printAgeAndHobbies
, which is a method on the myDoggo
object. But this.age
is also inside the same method, you might say. Well, yes and no.
this.age
is actually inside a call back function which is inside the forEach
method inside the printAgeAndHobbies
method. Say what? So, we are using a method called forEach
. It works with arrays and calls an anonymous function (callback) on every item of the array. So technically, the callback inside which this.age
is used is a regular function and not a method on an object. I hope that's clear.
The way we can fix this particular situation is by adding a second parameter to the forEach method (the first one being the call back function). We can pass an object as a second argument and the callback will reference that object. In our case the second argument will be this
. As said before, every this
we put inside a method on an object refers to that object. Since the second argument will be in the context of the printAgeAndHobbies
method, it will reference the myDoggo
object. Check the code bellow:
printAgeAndHobbies() {
this.hobbies.forEach(function(hobby) {console.log(hobby + this.age)}, this)
}
myDoggo.printAgeAndHobbies() // prints sleeping3 TV3 swimming3
I know it's a lot to wrap your head around, so I'm going to stop here for now. If something is still unclear, please ask in the comments and I'll try to give it another shot at explaining. In the next text we'll discuss more fixes and maybe introduce the ultimate fix, the ES6's fat arrow function.
Top comments (0)