WTF is this?

WTF is this?
7 min read

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 like toPrecision or toExponential. A String has functions like split or indexOf 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 extend Object, there are common properties and functions found on all JavaScript objects.

Make sense? Let's pull out a diagram:

what even are objects

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 (or let or const) 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:

  1. you call some_object.whatIsThis()
  2. you call some_object.another_object.nowWhatIsThis()
  3. you call new some_object.another_object.nowWhatIsThis()
var some_object = {
    'whatIsThis' : function(){
        console.log(this);
    },
    'another_object' : {
        'nowWhatIsThis': function(){
            console.log(this);
        }
    }
};

Answers

  1. some_object{whatIsThis: function, other_object: > Object} -- the some_object object
  2. {nowWhatIsThis: function} -- the some_object.another_object object
  3. nowWhatIsThis{} -- a new object that used the some_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:

  1. grabs the link from the DOM and assigns it to a variable.
  2. defines an onclick event on that variable as a function, which writes the value of this 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{}. Use addEventListener.

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 and apply do the same thing -- change the meaning of this in the function -- but do it a bit differently. call will allow you to pass a number of comma separated arguments to the function, while apply 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 :)