
WTF is this?
Since you've read about how important JavaScript is, I'm sure you've been dabbling and doing some work with it. That's awesome! I also know that you've had quite a few hiccups along the way. Don't worry, we're here to help.
One of the biggest issues for budding JavaScript developers is the keyword this,
and what value it holds. I'm gonna talk a bit about it and hopefully it will make your code a bit easier to reason with, allowing you to better understand the examples that you come across online.
Open up your console and write the code examples along with the article!
So, what is this
?
Short answer is that this
is the object that the code is currently bound to.
That probably leaves you with more questions like "wtf is an object
?" and "wtf is binding
?" Don't worry, I got you.
Let's start with objects. Just about everything in JavaScript is an object
; or a different way to explain it, is that Object
(big O) is the parent of just about everything. An object is simply a collection of variables, functions, and other objects.
When you read the word object
, I want you to think of these characters: {}
. Let's try it: Object. Did you think {}
? Good.
All JavaScripts objects have a parent (or Prototype, is the technical term) which provides them with some core functionality. The
Number
parent prototype offers functions liketoPrecision
ortoExponential
. AString
has functions likesplit
orindexOf
and so on.
So in thinking of an object
{}
, always know that its prototype adds some properties and functions to it behind the scenes. And since all objects extendObject
, there are common properties and functions found on all JavaScript objects.
Make sense? Let's pull out a diagram:
Simple enough, right? Let's get into scopes.
Globals and Scoping
Now that you know what JavaScript objects are, we can talk about scope. Every JavaScript environment has a global object that is available everywhere. In the browser it is the window
object; or in Node.js, it is the aptly titled GLOBAL
. So, again, think of that global object like this:
window = {};
When you define things in JavaScript -- a variable, a function, an object, etc. -- it is typically made apart of the object that it was declared in. Now this has a few exceptions: the most notorious, and the thing that will cause silent and hard to trace errors, are variables.
You can think of defining variables as assigning it (binding
) to an object:
var name = 'mark';
Is like saying:
window.name = 'mark';
(Because the object we're working in is window
). Now say we wanted to create a new object:
var your_object = {};
Following this logic, your_object
that we defined above is basically window.your_object
. Makes sense?
You have to be careful with variable definitions. If you don't put a
var
(orlet
orconst
) in front of a variable, that definition would float up and be assigned to the global object. That could cause some nasty problems, right? Always keep this in mind.
Functions are a bit different...
A function is an object, and has scope; however, once you call a function, it is used and disposed of. You no longer have access to the function itself, only the returned value.
function whatIsThis(){
console.log(this);
}
whatIsThis(); // window{}
In the example above, the whatIsThis
function will simply write the value of this
to the console when executed. In this case, this
is the window
object - because whatIsThis
is bound to its scope.
But, if you were to use the new
keyword:
new whatIsThis(); //whatIsThis{}
It's now acting as a template; and since it's a template, instead of writing to the console like before... it returns an object! And now, this
is the new object whatIsThis{}
. Psh, that's so easy.
Now, what if we put a function in an object?
var some_object = {
'whatIsThis' : function(){
console.log(this);
}
};
Calling some_object.whatIsThis();
will write some_object{whatIsThis: function}
to the console - because in this case, the whatIsThis
function is bound to the scope of some_object
.
Take a look at the object below and try to figure out what is written to the console when:
- you call
some_object.whatIsThis()
- you call
some_object.another_object.nowWhatIsThis()
- you call
new some_object.another_object.nowWhatIsThis()
var some_object = {
'whatIsThis' : function(){
console.log(this);
},
'another_object' : {
'nowWhatIsThis': function(){
console.log(this);
}
}
};
Answers
some_object{whatIsThis: function, other_object: > Object}
-- thesome_object
object{nowWhatIsThis: function}
-- thesome_object.another_object
objectnowWhatIsThis{}
-- a new object that used thesome_object.another_object.nowWhatIsThis
function as a template
Did you get 'em right?
The main takeaway is that this
is the closest parent object {}
of where your function is being executed. If that function is called with the new
keyword, this
is the newly created object.
Augmenting this
Since just about everything in JavaScript is an object, just about everything in JavaScript has potential to be the value of this
. The most common example for web developers will be adding event handlers to objects returned from the DOM
.
The DOM (Document Object Model) is a virtual representation of your markup (HTML) that JavaScript has access to.
Event Handlers
Lets say you have a link on a webpage that you want to add a click event to, it would look something like this:
<a href="#" id="my_link">My Link</a>
....
var my_link = document.getElementById('my_link');
my_link.onclick = function(){
console.log(this);
};
The code simply:
- grabs the link from the
DOM
and assigns it to a variable. - defines an
onclick
event on that variable as a function, which writes the value ofthis
to the console
What do you think is the value of this
in this scenario? The answer shouldn't surprise you - "just about everything in JavaScript is an object."
That variable my_link
, when we ran document.getElementById
? It was assigned an object: my_link{}
. When we create the onclick
function, it's being attached to that object. Now remember above when we executed some_object.whatIsThis()
and found out that this
was some_object
? In this example, this
is the hyperlink object! If you were to click the link, what you'd see in the console is <a href="#" id="my_link">My Link</a>
(clicking the link is telling the browser to execute my_link.onclick(DOMEvent)
, which would execute console.log
).
You should not add event handlers this way, I did this to help illustrate how functions are added to our imaginary object
{}
. UseaddEventListener
.
Changing this
at execution time
JavaScript is a neat little language. There are tons of little things you can do with it that isn't possible in most other languages that you come across. One of those things is changing this
whenever you want to. This can be done in a number of ways, but we'll take a look at call
and apply
.
Both
call
andapply
do the same thing -- change the meaning ofthis
in the function -- but do it a bit differently.call
will allow you to pass a number of comma separated arguments to the function, whileapply
requires the arguments to be in an array. Each approach has its benefits.
Lets say we have this object my_object
as defined below. When we call my_object.fullName()
it would write "Mark Henderson" to the console.
var my_object = {
'f_name': 'Mark',
'l_name': 'Henderson',
'fullName': function(){
return this.f_name + ' ' + this.l_name;
}
};
But what if you needed to write some other name to the console? You could define another object with a fullName
method, you could augment the signature of my_object.fullName
to pass in a first and last name, or you can do something cool using JavaScript the way it was intended.
Looking at that fullName
function, it looks like it only needs an object with f_name
and l_name
defined.
var jermaine_object = {
'f_name': "Jer'Maine",
'l_name': "Fincher"
};
That looks good, but how do I replace the this
in that fullName
function? Use either call
or apply
:
my_object.fullName.call(jermaine_object);
Running that code will write "Jer'Maine Fincher" to the console.
Woah, woah, what?
I know, let me explain. It all goes back to "just about everything in JavaScript is an object," and we know that functions are no different. Think of a function as an executable object{}
: we know that objects can have variables and functions bound to it. In this case we, are simply using the call
function that is bound to the fullName
function. If we could take a special look at the structure of my_object
, it would look something like this:
my_object<Object>{
f_name<Object>,
l_name<Object>,
fullName<Function>{
call<Function>,
apply<Function>,
name<String>,
arguments<Array-Like-Object>,
...
}
}
If we executed console.log(my_object.fullName.name)
it would write "fullName" to the console. We can treat the fullName
function like any other JavaScript object (but only before we execute the function, with parenthesis ()
at the end of it).
So what does my_object.fullName.call(jermaine_object);
do? It simply runs the call
function on the fullName
function. What does call
do? Like apply
, it simply redefines what this
represents in the function, and calls it. It does not permanently redefine this
, but only changes while the call
function is running.
Since we know that this
represents the object that that the function is scoped to, calling my_object.fullName();
can be thought of like:
var my_object = {
...
'fullName': function(){
return my_object.f_name + ' ' + my_object.l_name;
}
};
(I replaced this
with my_object
)
So calling my_object.fullName.call(jermaine_object);
, where call
replaces this
, can be thought of as:
var my_object = {
...
'fullName': function(){
return jermaine_object.f_name + ' ' + jermaine_object.l_name;
}
};
(jermaine_object
is the new this
, but only for the one time)
Next Steps
Understanding what this
is and keeping track of when it potentially changes could be an exercise in itself. There are a lot of ways to change what this
means: Function.call
, Function.apply
, Function.bind
(this is a good one as it doesn't execute the function immediately, but creates a new one to be executed), Object.addEventHandler
, and so on.
There are tons of resources online that will help you better understand this
, but the best one is to practice. Write some code, use this
in your code (don't be scared), and the keyword will naturally become an integral part of your JavaScript toolkit.
Have you joined yet? What are you waiting for?! Go to www.datcode.io to join our vibrant community of black and brown coders. (You don't have to be brown, but you gotta love us, though :)