Essential "this" concepts in JavaScript
Tags: javascript, beginners, programming, codenewbie
Published: 2022-07-25 16:47:00

## Execution context, implicit and explicit binding, arrow functions, and of course, this.

To me, a competent  understanding of the keyword `this` in JavaScript feels just about as hard to master as the final boss in a D&D campaign.

I am not prepared.

My instinct therefore tells me I should write an article on the subject so that I can attempt to move `this` from my **passive** vocabulary to my **active** vocabulary.

Join me on this quest, and let's level up together.

### Levels 1–4: Local Heroes
_Defining execution context, `this`, and `new`._

Before we look at `this`, it will be helpful to define **execution context**. MDN describes [execution context](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth#javascript_execution_contexts) in this way:

> _When a fragment of JavaScript code runs, it runs inside an execution context. There are three types of code that create a new execution context:_

> _The global context is the execution context created to run the main body of your code; that is, any code that exists outside of a JavaScript function._

> _Each function is run within its own execution context. This is frequently referred to as a "local context."
Using the ill-advised [`eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) function also creates a new execution context._

> _Each context is, in essence, a level of scope within your code. As one of these code segments begins execution, a new context is constructed in which to run it; that context is then destroyed when the code exits._

Put simply, **an execution context is a created space that directly surrounds a block of running code**.

A **global** context is created at the start of a program. Each time a function is invoked, a **local** execution context gets created and is added to the execution context stack (the call stack).

I see other articles refer to execution context as the "environment" surrounding your block of running code, which makes sense, because it's more than just a location!

**An execution context also has custom properties.**

These properties are a little different between global and local context, and between different types of local context (functions vs arrow functions vs classes, etc).

Something that **every** execution context has however, is a property known as `this`.

So what is `this`?

**Drum roll…**

**`this` is a reference to an object.**

But what object? Well, that depends. Time to run through some examples to start figuring it out.

In our first simple example, we log the value of `this` in the global execution context, outside of any function:

```javascript
console.log(this); // window
```

In the browser, we see that `this` equals the `window` object.

MDN confirms the behavior in [this definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#global_context):

> _In the global execution context (outside of any function), `this` refers to the global object whether in strict mode or not._

**SIDE NOTE:** In the browser the global object is `window`. In Node.js, the global object is actually an object called `global`. There are some slight behavioral differences though. In Node.js, the example above would actually log the current `module.exports` object, not the `global` object. 🤷 Let's avoid that rabbit hole for now.

In this next example, we log `this` inside a function:

```javascript
function logThisInAFunction() {
    console.log(this);
};

logThisInAFunction(); // window
```

At first, you might think that `this` will evaluate to something other than `window`, seeing as we created a new local execution context upon invoking the function, which the code inside our function runs within.

But as a default (when **not** using [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), another rabbit hole 🤷‍), unless **explicitly** set (which we will get to), `this` still references `window`.

MDN confirms this [default behavior](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#function_context):

> _Inside a function, the value of `this` depends on how the function is called._

> _Since the following code is not in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), and because the value of `this` is not set by the call, `this` will default to the global object, which is [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) in a browser._

**SIDE NOTE:** There is a weird difference in behavior between the browser and Node.js in this second example. In the browser, `this` equals `window`, but in Node.js, `this` equals `global` this time, instead of the `module.exports` object. This is due to the difference in how Node.js handles the default value of `this` between global and local contexts.

The next example expands on `this` having a different value based on **how** the function is called:

```javascript
function logThisInAFunction() {
    console.log(this);
};

const myImportantObject = {
    logThisInMyObject: logThisInAFunction
};

logThisInAFunction(); // window

myImportantObject.logThisInMyObject(); // myImportantObject
```

When we call `logThisInAFunction()` and `myImportantObject.logThisInMyObject()`, the same function is ultimately being invoked. However, the value of `this` is not the same for the two invocations. [MDN again eloquently describes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#as_an_object_method):

> _When a function is called as a method of an object, its `this` is set to the object the method is called on._

Put simply, if you call a function as a method of an object, that object is going to become the value for `this` instead of the global object. In this way, we are **implicitly** binding the value of `this` to an object of our choosing.

The next example looks at how `this` behaves for **classes**:

```javascript
class MyAwesomeClass {
    constructor() {
        console.log(this);
    };
};

const awesomeClassInstance = new MyAwesomeClass(); // MyAwesomeClass {}
```

When creating an instance of a class using the `new` keyword, a new empty object is created and set as the value of `this`. Any properties added to `this` in the constructor will be properties on that object.

[As MDN puts it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#class_context):

> _The behavior of `this` in [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) and functions is similar, since classes are functions under the hood. But there are some differences and caveats._

> _Within a class constructor, `this` is a regular object. All non-static methods within the class are added to the prototype of `this`._

Relatively straight forward.

#### Before we level up…

Hopefully `this` is starting to sink in. Having already talked about **implicit** binding, let us explore the next level: **explicit** binding.

### Levels 5–10: Heroes of the Realm
_Defining `call`, `apply`, and `bind`._

Earlier we saw how we can take a function, add it as a method to an object, and when we invoke that method, that object **implicitly** becomes our new value for `this`.

Now we want to learn how to **explicitly** set the value of `this` when invoking a function. We can do that with a few different methods: `call`, `apply`, and `bind`.

First, an example using `call`:

```javascript
const wizard = {
    class: 'Wizard',
    favoriteSpell: 'fireball'
};

const warlock = {
    class: 'Warlock',
    favoriteSpell: 'eldrich blast'
};

function useFavoriteSpell(name) {
    console.log(`${name} the ${this.class} used ${this.favoriteSpell}!`);
};

useFavoriteSpell('Bobby'); // Bobby the undefined used undefined!

useFavoriteSpell.call(wizard, 'Bradston'); // Bradston the Wizard used fireball!

useFavoriteSpell.call(warlock, 'Matt'); // Matt the Warlock used eldrich blast!
```

The first time we invoke `useFavoriteSpell`, we have undefined values. `this` has defaulted to referencing the `window` object, and the properties `class` and `favoriteSpell` do not exist on window.

The next two times we invoke `useFavoriteSpell`, we are using `call` to assign the value of `this` to the object of our choosing, and also invoking the function.

That is what `call` does! The first argument of `call` is the object you want `this` to equal, and the subsequent comma separated arguments are the function arguments.

You can read more about `call` [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call).

The next method we will look at is `apply`. No additional code example is necessary to understand it, in my opinion. The main difference between `call` and `apply` is this:

- `call` accepts function arguments one by one in a comma separated list. 

- `apply` instead accepts all function arguments as one array.

Outside of some other small differences, they do the same thing. You can read further about `apply` [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply).

Finally, we have `bind`:

```javascript
const wizard = {
    class: 'Wizard',
    favoriteSpell: 'fireball'
};

const warlock = {
    class: 'Warlock',
    favoriteSpell: 'eldrich blast'
};

function useFavoriteSpell(name) {
    console.log(`${name} the ${this.class} used ${this.favoriteSpell}!`);
};

useFavoriteSpell('Bobby'); // Bobby the undefined used undefined!

const useFavoriteWizardSpell = useFavoriteSpell.bind(wizard);

useFavoriteWizardSpell('Bradston'); // Bradston the Wizard used fireball!

const useFavoriteWarlockSpell = useFavoriteSpell.bind(warlock);

useFavoriteWarlockSpell('Matt'); // Matt the Warlock used eldrich blast!
```

Instead of setting the value of `this` and also invoking the function, calling `bind` on our function **just returns a new function**, whose `this` value is now equal to the object we passed as the argument of `bind`.

We can then call our new function whenever we want, and the value of `this` has already been set.

Read more on `bind` [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).

#### Before we level up…

So now we know about execution context, `this`, and how to set a value for `this` both implicitly, and explicitly with `call`, `bind`, and `apply`.

What else is there? To be honest, there is a lot. But let's focus on one thing at a time, and move on to the relationship between `this` and arrow functions.

### Levels 11–16: Masters of the Realm
_How arrow functions affect `this`._

Earlier, I said that every execution context has a property known as `this`. The behavior with arrow functions is a little different, however.

While the local execution context created by invoking an arrow function **does** still have a value for `this`, it **does not define it for itself**. It instead will retain the value of `this` that was set by the next outer execution context from where the function was invoked.

For example:

```javascript
const logThisInAnArrowFunction = () => {
    console.log(this);
};

const myImportantObject = {
    logThisInMyObject: logThisInAnArrowFunction
};

logThisInAnArrowFunction(); // window

myImportantObject.logThisInMyObject(); // window
```

We see when we call `myImportantObject.logThisInMyObject()` that even though a new local execution context was created, `this` is going to get its value from the next outer execution context. In this case, it is the global execution context. Therefore, `this` remains a reference to the `window` object.

Here is another example that hopefully will drive it home:

```javascript
const myImportantObject = {
    exampleOne: function() {
        const logThis = function() {
            console.log(this);
        };
        logThis();
    },
    exampleTwo: function() {
        const logThis = () => {
            console.log(this);
        };
        logThis();
    }
};


myImportantObject.exampleOne() // window

myImportantObject.exampleTwo() // myImportantObject
```

In this example we have two methods we call from `myImportantObject`: `exampleOne()` and `exampleTwo()`.

When we call `myImportantObject.exampleOne()`, we are invoking that function as a method of an object, and therefore, `this` equals `myImportantObject` in that local context.

However, inside that function, we define another function and then execute it.

As previously mentioned, unless **explicitly** set, and unless the function is being invoked as a method of an object, `this` references the global object, `window`. Therefore, we see `window` logged.

When we call `myImportantObject.exampleTwo()` however, something different happens. The first part is the same: `this` equals `myImportantObject` inside `exampleTwo`. Next, we define an arrow function and then execute it. The difference is, **the arrow function does not define its own value for `this`!** It instead retains the value of `this` from the next outer execution context, which in this example, was the local context created by `myImportantObject.exampleTwo()`, where this equalled `myImportantObject`. So that is what we see logged.

#### Before we level up…
Arrows functions differ from regular functions in plenty of other ways. If you want to read more, [check out MDN's page on the topic](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions).

If you have made it to this point in the article, it should hopefully mean that things are starting to sink in. Take a moment to relish in your achievement.

There's only one section left. Let's dive in.

### Levels 17–20: Masters of the World
_Callbacks._

Before I started writing this article, I thought the last section was going to be the most difficult to tackle. In the past, examples of how `this` got its value in callback functions confused me.

With the context I now have, it no longer feels like callback functions add any more complexity to how `this` works. We just need to consider what we already know about execution context, and how we invoke a function.

I guess the final boss is starting to look a little more beatable 😁.

Here is an example of using `this` within callback functions. See if you can guess what the values logged for each will be:

```javascript
function higherOrderFunction(callback) {
    const myImportantObject = {
        callMyCallback: callback
    };
    myImportantObject.callMyCallback();
};

function callbackFunction() {
    console.log(this);
};

const callbackArrowFunction = () => {
    console.log(this);
};


higherOrderFunction(callbackFunction);
higherOrderFunction(callbackArrowFunction);
```

Starting with our first function call (where the argument is `callbackFunction`):

- `higherOrderFunction` is invoked, and creates a local execution context. Because it is not implicitly or explicitly set, `this` defaults to `window`.

- Our callback function is invoked inside `higherOrderFunction` via `myImportantObject.callMyCallback()`. Because our callback is **not** an arrow function, the created local execution context defines its own `this`. And, because that function is being invoked as a method of `myImportantObject`, `this` equals `myImportantObject`.

Next, let's look at the second function call (where our argument is `callbackArrowFunction`):

- `higherOrderFunction` is invoked just as before. Same outcome: `this` equals `window` in that local context.

- Our callback is once again invoked inside `higherOrderFunction`. This time, because our callback **is** an arrow function, it **does not** define its own `this`. So even though it is being invoked as a method of `myImportantObject`, `this` retains the value of the next outer execution context, which was `window`.

The moral of the story is, callback functions add complexity only in the sense that you have to consider **how** (and also **where** for arrow functions) the callback is being invoked.

**But we were considering that already!**

The difference is that callback functions are passed as arguments to other functions, and so where and how they get invoked is a little different.

#### Parting Thoughts

Hopefully I didn't lose you at some point 😅.

As a developer, I am always trying to continue my education - and I recognize that there is [still so much I do not know](https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect).

`this` is a big subject, and I am sure that there are aspects of the concept that I missed, or examples and explanations that could be improved. **Let's help each other by trying to figure out what those were!** Feel free to leave a comment, and let me know if this article helped you, and/or what could have been improved.

Thanks for reading! 😄 Check out some of my earlier articles at [quickwinswithcode.com](https://www.quickwinswithcode.com/).


#### Resources

- [In depth: Microtasks and the JavaScript runtime environment](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth)

- [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)

- [Strict Mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)

- [`Function.prototype.call()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)

- [`Function.prototype.apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)

- [`Function.prototype.bind()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)

- [Arrow function expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)