Back to Basics: Understanding and Conquering "this" in Javascript
Tags: javascript, webdev, beginners, react
Published: 2021-03-29 11:36:43

---
title: Back to Basics: Understanding and Conquering "this" in Javascript
published: true
description: Understanding the dark magic of function context in Javascript and Typescript
tags: javascript, webdev, beginners, react
canonical_url: https://blog.zack.computer/taming-this-in-javascript
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1617014746497/ic0F1Cipg.jpeg?w=1600&h=840&fit=crop&crop=entropy&auto=compress
---

I've been thinking about `this` a lot recently because I've been messing around with a lot of chained callback functions in my web code. This is a good opportunity to go back to basics and recap how `this` works in Javascript and what tools exist to tame its quirks.

For new developers coming from a more typically object-oriented language like Java or Swift, Javascript's weird use of the `this` keyword is a trap waiting to crash your code at any moment. This is especially dangerous if you're using React's class components, where you're often defining methods on your class to act as a callback handler. If you blindly assume that `this` is going to behave the way you've come to expect, you're gonna have a bad time. So, let's understand `this` enemy so we can learn how to fight it:

## What is `this`

![What's This](https://media.giphy.com/media/ZpNEeC9UmJw9AOGoSb/giphy.gif)

Let's start with the basics of how we expect `this` to work under the best circumstances:

```javascript
'use strict';

class Person {
  name;

  constructor(theirName) {
    this.name = theirName;
  }

  introduce() {
    console.log("Hello I'm " + this.name);
  }
}

const william = new Person("Bill");
william.introduce(); // Prints out "Hello I'm Bill"
```

This is pretty straightforward: there is a class of object called `Person`. Each `Person` remembers a variable called `name` and has a method called `introduce`. When you call `introduce` on a person it looks at that person's `name` and prints an introduction. **So, `this` is a reference to the object whose instance of `introduce` we're looking at, right?**

Well, not quite. Take a look at this:

```javascript
// Continued from above

// This doesn't RUN william's introduce function,
// it makes a REFERENCE to it
const introduceWilliam = william.introduce;

// Because it's a reference to a method that worked,
// we might assume the reference will also work but...
introduceWilliam();
// Uncaught TypeError! Cannot read property 'name' of undefined
```

Now we've delved below the calm surface into the dark depths of a functional programming language written in the 90's.

You have to remember that as far as Javascript is concerned **functions are just another kind of object**. They can be stored, passed around, and executed anywhere.

When you call `someThing.someFunc()`, Javascript parses that you want to **execute the instructions in `someFunc` in the context of `someThing`**. That is to say, set `this` to `someThing` and then execute the instructions.

But if you make a reference to `someFunc`, you could execute it anywhere. Above, we called it in the global context, which leaves `this` as `undefined` when you're in strict mode. You can even use the function's [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) or [`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) methods (functions on a function!) to provide any context and args you desire.

Let's write some mildly horrifying code to demonstrate this:

```javascript
// Still using william from above
const william = new Person("Bill");
// Make a reference to william's introduce method
let introduce = william.introduce;

// Make an unrelated object - Bagel the Beagle
const puppy = { name: "Bagel", breed: "Beagle" };
// Run function with manual `this` - Dogs can talk now
introduce.call(puppy); // Prints "Hello I'm Bagel"
```

## Taming `this` Beast

This `this` is incredibly, and often unnecessarily, powerful. Like many incredibly powerful things, it is also incredibly dangerous. Because of how often we pass around references to functions - to use as callbacks for `button`s or `form`s, for example - the unbound nature of `this` is just lying in wait to trip you up.

So how do we tame `this`? I could shake my cane at you and croak *"Well, back in **my** day..."* but the truth is that the ES5 and ES2015 revisions to Javascript gave us everything we need to clamp down wandering `this` values:

### Function.prototype.bind()

Added in ES5, the first tool we got was the  [`bind()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) function, a standardization of `this` hacks that the various utility libraries of the 2000's had innovated. 

```javascript
// Bind this reference to introduce so this is ALWAYS william.
let alwaysIntroduceWilliam = william.introduce.bind(william);

alwaysIntroduceWilliam(); // Prints "Hello I'm Bill"
alwaysIntroduceWilliam.call(puppy); // Prints "Hello I'm Bill"
```

`bind` does what it says on the tin. It binds the function to a chosen `this` - ensuring that the instructions inside are **always** run in the context we choose. Here you can see that even if we try to use `call` to set a different `this`, the `bind` overpowers and we're always introducing `william`. This was a great first step towards fixing `this`, but these days is less commonly used because of...

### Arrow'd =>

Added in ES2015, arrow functions gave us (almost accidentally) the most common way of fixing `this` to the value that we expect. This is because an arrow function **creates a closure over the context in which it was defined.** What that means is that all the variables referenced inside the arrow will always reference the same points in memory as when the arrow was first parsed.

This is incredibly useful for capturing local variables so that they can be used later, but it has the added benefit of capturing the value of `this` that was set when the arrow was defined. And, since `this` is (basically) always going to be the object being created during construction, we can use arrow functions to make methods where `this` will behave exactly like we expect:

```javascript
// Rewriting Person with arrows
class ArrowPerson {
  name;

  constructor(theirName) {
    this.name = theirName;
  }

  introduce = () => {
    // The arrow captures `this` so it is actually a
    // reference to THIS Person.
    console.log("Hello I'm " + this.name);
  }
}

const arrowBill = new ArrowPerson("Arrow Bill");
arrowBill.introduce(); // "Hello I'm Arrow Bill"

// Now `this` is fixed even as we pass the function around:
const introduceRef = arrowBill.introduce;
introduceRef(); // "Hello I'm Arrow Bill"
introduceRef.call(puppy); // "Hello I'm Arrow Bill"
```

## `this` all makes more sense now

I hope you understand `this` a little bit better now. To be honest, I think I understand it better just from *writing* this all out. And, because the Javascript `this` can affect all your code that transpiles into Javascript, hopefully this will also help you understand the twists and turns of function context in other languages like Typescript.

If you have any questions about `this`, drop them in the comments below. Even after years writing for the web, I'm still learning so I'm sure there are terrible dangers and cool facts about `this` I forgot or don't yet know.