What's this? What's this? There's something very wrong
this
is probably one of the hardest concepts to grasp in Javascript. Not because it's complicated, but because it's one of things of the Javascript language that developers need to memorize in order to understand how it works in specific scenarios. I'll try to explain what is this
all about and yes, there are going to be tons of puns.
What's this? What's this?
First, this
is a pointer, a reference to an object. It's created whenever a function it's created and lives inside its scope in the same way the arguments
variable. One major difference with the arguments
variable is that you can't modify it's value.
function() { arguments = [] } // no error
function() { this = {} } // throws ReferenceError: Invalid left-hand side in assignment
The object this
points to refers to the object of which that function is a property/method. In Web Development, most of the time we are calling functions through the Global/Head, the window
object inside our Browser, where all our Javascript object is being stored. In your favorite console, if you type this
, you get the aforementioned Global/Head object.
`this` // returns Window
So in which scenarios does the this
object changes its value from the Global/Head object? Here are them:
- Whenever a function is called,
apply
orcall
are used. - Whenever a nested function is called
- Whenever a function is called with the
new
keyword
Whenever a function is called, apply or call are used.
Let's start with the following object
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + pumpkin.name + "! The pumpkin " + pumpkin.status}
}
If you create this in your console, you will see that when you call pumpkin.whoGrewSoTired()
will actually display a proper message (or lament if you will). This is because the variables pumpkin.name
and pumpkin.status
are actually browsable from the Head/Global object window
. This would be the same as writing
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + window.pumpkin.name + "! The pumpkin " + window.pumpkin.status}
}
Now, you most likely had never seen this before (if you have, please send me the email of the developer, I will introduce him/her to a Oogie Boogie friend I have). The reason is because most developers in their good senses are aware of Object Oriented Programming (OOP) and what they want is to call the actual properties of the object. And this
, my friends, is what this
is for.
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + this.name + "! The pumpkin " + this.status}
}
So how does this
changes when we call a function? In the previous code we had no problem in seeing that we are retrieving the name and status of the object pumpkin
. Now see the following code:
var season = "Christmas"
var halloweenTown = { season: "Halloween" }
var getHoliday = function() { return this.season }
halloweenTown.getHoliday = getHoliday;
halloweenTown.getHoliday() // returns "Halloween"
getHoliday() // returns "Christmas"
Why are we retrieving the value "Halloween" for town? Well, because the value of this
during the execution of that function is the object town, while on the latter it's the object window. Since we are storing all our variables in the Head/Global object, this would be the same as before:
window.halloweenTown.getHoliday()
window.getHoliday()
Now, do you remember those Object methods call
and apply
? I bet they make more sense now with this example!
getHoliday.call(halloweenTown, null)
getHoliday.call(window, null)
Basically, we are telling to the function getHoliday
which value this
should have. Let's move on to the next case!
Whenever a nested function is called
Now, there's a special case when this
may get a little confused: nested functions. See the following code.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
Run town.whosTheKing()
and wow, you get 'undefined is the king of Christmas Town'. What's this? What happened to Santa? Was he kidnapped? Most likely, but the true problem is that the second this
was no longer referring to thte town
object! You might say "Well, that's obvious, because this
is being called by the whosTheKing
function, and not town
unlike the first one!". So, would you be happy if I do this?
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
var king = this.king;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
Run it. "undefined is the king of Christmas Town". If you are shocked by this
, keep reading!
(I actually did something in purpose in order to keep this error. To find it, you just need to read this answer in StackOverflow that explains the difference between using var and not using it)
Ok, so what's going on? Here's the answer: In ECMAScript 262 Ed.3, nested functions "lose" the reference to this
value. Whenever they "lose" it, they refer to the Head/Global object. So the second function is actually looking outputting the window.king
variable. I can prove it here:
window.king = "Jack"
town.whosTheKing(); // "Jack is the king of Christmas Town"
The good news is that in ECMAScript 262 Ed. 5 this is getting solved. In the meantime, a work around that you have probably seen in some code goes like this.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
that = this;
var getKing = function() {
return that.king
}();
return getKing + " is the king of "+ town
}
}
town.whosTheKing(); // "Santa is the king of Christmas Town"
In order to not lose the reference, we use a helper variable that stores the correct pointer to our variable. Another work around is to use a Closure that stores the variable with the proper scope. This, however, can get confusing really fast.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
king = this.king;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
town.whosTheKing(); // "Santa is the king of Christmas Town"
(If you don't understand this, I suggest you to read the note I put previously about the StackOverflow answer)
Whenever a function is called with the new keyword
Ok, so we are almost through all the behaviours of this
; the missing one is when the new
word comes to town (got it? to town! Ah, fine, I'll stop). Let me ask you, what do you think the value of boogieMan.phrase
will be?
var Monster = function(phrase) {
this.phrase = phrase;
}
var boogieMan = Monster("YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!");
boogieMan.phrase // returns ??
It will return an error. Why? Because despite our bulletproof OOP design, we are just calling a function that returns undefined
(all functions return a value, even if it's undefined
). Without the new
keyword, you just set up window.phrase
instead of an instance of the "class" Monster with a property phrase
.
When a function is invoked with the new
keyword, the value of this
refers to the object itself, which is proper OOP design. From our previous code:
var Monster = function(phrase) {
this.phrase = phrase;
}
var boogieMan = new Monster("YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!");
boogieMan.phrase // returns "YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!"
What if the object doesn't have the property we are looking for? Javascript will start looking up in the prototype chain for the right value, and thus the value of this
will be updated accordingly.
var Monster = function(phrase) {
if(phrase) this.phrase = phrase;
}
Object.prototype.phrase = "Eureka! This year, Christmas will be OURS";
var pumpkinKing = new Monster(); // We don't set the the property 'phrase'
pumpkinKing.phrase // returns "Eureka! This year, Christmas will be OURS"
In the previous code this
first looked up in the Monster
object; when it failed to find the property phrase
, it started the prototype lookup process, where it found the phrase
property as part of the Object prototype, the truly king of objects!
Hopefully this helped devs out there to understand better the this
word. No Christmas or Halloween towns were damaged in the process of making this article.
Written by Jose Jesus Perez Aguinaga
Related protips
9 Responses
Good writing. Enjoyed reading it. Keep it up.
@mutahhir Glad to know you enjoyed it, was worried I made it too tedious. Thanks!
function() { arguments = [] } // no error
maybe it need a function name
Thanks for sharing this dude
Awesome overview! I wonder, when you introduce the that = this
pattern, doesn't that
become a global variable because you aren't defining a local variable with var
?
Just personal preference, but I prefer _this to that.
@eallam That's correct! That's pretty much the reason why this.king
works if we use king = this.king
instead of var king = this.king
in the last example of that section. It's stored in the window
object!
@stevefrost I actually prefer self
; I am a little kid who was spoiled with python at some point of my life :)
@jjperezaguinaga while @eallam was correct about creating the global, you don't need a global. You could have used var that = this;
and the next function would have maintained a reference through closure.