The JavaScript this Keyword
Tags: javascript
Published: 2020-03-30 15:25:20

---
title: The JavaScript this Keyword
published: true
date: 2020-03-30 06:00:00 UTC
tags: javascript
canonical_url: https://www.prestonlamb.com/blog/javascript-this-keyword
---

## [tldr;](#tldr)

The `this` keyword in JavaScript is one of the most confusing parts of the language, but understanding how it works and to what it is referring is vital to writing applications with as few errors as possible. We’ll go over a couple methods of figuring out what `this` is referring to so that you can figure it out in your application. There are a few methods for figuring out what `this` is referencing in a function, and we’ll cover them in this article.

## [What is `this`?](#what-is-this)

Before we figure out what `this` is referring to, let’s figure out what `this` is in the first place. When talking about `this` in JavaScript, we’re talking about the context in which a JavaScript function is run. Context in general is the circumstances that form the setting for an event, statement, or idea. So in JavaScript, it’s the circumstances in which something is done (like a function being run, for example). `this` in JavaScript is generally related to objects, and what object is invoking a function. `this` will refer to an object available inside the function that’s being executed. That object changes depending on where the function is being executed, and much of the time depends on the object that calls the function.

Let’s take the following example and look at how its context will change in two different scenarios:

```js
function sayHello() {
  console.log(this);
  console.log(`Hello, ${this.name}!`);
}

const person = {
  name: 'Preston',
  sayHello,
};

sayHello(); // Window {}; Hello, !
person.sayHello(); // { name: "Preston", sayHello: function }; Hello, Preston!
```

The context of the `sayHello` function changes depending on how and where it’s called. When it’s invoked by itself, its context is the global `Window` object. When it’s invoked from the person object, its context is the `person` object that invoked the function.

This concept of context is pretty natural to us in our communication with others. Suppose your friend asks you, “Hey, did you see the game last night? It was great!” You know intuitively that “it” is referring to the game. You can tell that because of the context of the conversation. But if you say to your friend, “Man, it’s crazy out there,” they don’t know exactly what you’re referring to. But as humans we’ve come to understand that that sentence just means things going on in the world are crazy. It’s more of a global statement as opposed to a specific statement like the first one. When we’re speaking of `this` in JavaScript, we are trying to determine what the context of the function is, just like in these two sentences.

## [Global Context](#global-context)

In our example with the `sayHello` function above, `this` prints out in two different ways, once as the `Window` object and once as `myObj`. Let’s look at the first way that it prints out, which is the global context. If a function is called and it’s not called as a method on an object, the context of the function will default to the global context. The exception here is if you are using the `new` keyword, which we’ll cover below. In the following example the function is called, but not called on an object. So the context is the global `Window`, and if there’s no `name` attribute on the `Window`, our message will print out as shown below:

```js
function sayHello() {
  console.log(this); // Window
  console.log(`Hello, ${this.name}!`); // Hello, !
}
sayHello();
```

> Note: this is assuming that you are running this function in a browser. If you were running it in Node, `this` would refer to a global object with information related to Node.js.

The global `Window` context is the catch-all context in JavaScript applications. Now there is one situation when this is not true, and that’s if you’re running your application in strict mode:

```js
'use strict';

function sayHello() {
  console.log(this); // undefined
  console.log(`Hello, ${this.name}!`); // Uncaught: TypeError: Cannot read property 'name' of undefined
}
sayHello();
```

If you’re running in strict mode, and the function isn’t run in a situation where it has a specific context, then `this` will be undefined instead of defaulting to the `Window`.

## [Determining Context](#determining-context)

The context in most situations in a JavaScript application are set on a function level. There are a few ways for the context, or the `this` object, of a function to be determined. Let’s look at the first way, when the function is a method on an object.

```js
const person = {
  name: 'Preston',
  sayHello: function() {
    console.log(this);
    console.log(`Hello ${this.name}!`);
  },
};
person.sayHello(); // { name: 'Preston', sayHello: function }; Hello Preston!
```

In this example, the `sayHello` function is a method on the `person` object. When it’s invoked, it’s run in the context of the `person` object. So, `this` refers to the object associated with calling the function. Many times you can determine what the context of a function is by looking to the left of the function name. If there’s a dot, look to the left of that. Whatever that object is, is the context of the function.

In the above example, you could also replace `this` with `person`. When you determine the context of the function, you can replace `this` with the related object. Instead of saying `this.name`, you could use `person.name`. Now, if you’re trying to have a function not be tied to the variable name you wouldn’t actually want to do that, but I point this out so you know `this` refers to the object that called the method. Hopefully that clears up what the context is a little bit.

Now, it’s important to realize that the context isn’t limited to only the top level object where it’s called. Let’s look at this example to see what I mean when I say that:

```js
function sayHello() {
  console.log(this);
  console.log(`Hello ${this.name}!`);
}

const person = {
  name: 'Preston',
  sayHello,
  spouse: {
    name: 'Amanda',
    sayHello,
  },
};
person.sayHello(); // { name: 'Preston', sayHello: function, spouse: {} }; Hello Preston
person.spouse.sayHello(); // { name: 'Amanda', sayHello: function }; Hello Amanda
```

In the above example, one of the attributes on the `person` object is an object itself. It also has a `sayHello` function. When we call the `person.spouse.sayHello()` function, `this` refers to the `person.spouse` object, not the `person` object. We can tell that in the same way we did before. We look at the `sayHello()` function and move left. There’s a dot, so we go left once more and the object is `spouse`.

I want to point out one other thing. It’s important to know that the above method of determining the context relates just to objects, but not arrays. Let’s look at what happens if we look at `this` in the `forEach` method on an array.

```js
const numbers = [1];
numbers.forEach(function() {
  console.log(this); // Window
});
```

So make sure when you are trying to determine the context that you remember to look for objects to the left of the dot, and not arrays or strings or other variables.

So we’ve looked at how we determine the context of a method on an object, now let’s look at ways that you can explicitly set the context for a function that isn’t a method on an object. Let’s look at the following example:

```js
function sayHello() {
  console.log(this);
  console.log(`Hello, ${this.name}!`);
}

const person = {
  name: 'Preston',
};
```

We still have our `sayHello` function, and our `person` object, but this time the object doesn’t have a `sayHello` method. We know that if we run the `sayHello` function without it being on an object, the context would default to the `Window`. But all JavaScript functions have three methods that you can use to set the context. Those three methods are `call`, `apply`, and `bind`. They all allow you to set the context of a function, although each in slightly different ways. We won’t go into detail of how these methods work, but it’s good to know that they exist and what they do. Let’s call the `sayHello` function and explicitly set the context:

```js
sayHello.call(person); // { name: 'Preston' }; Hello Preston!
// or
sayHello.apply(person); // { name: 'Preston' }; Hello Preston!
// or
const newFn = sayHello.bind(person);
newFn(); // { name: 'Preston' }; Hello Preston!
```

Again, these all have slight differences in how they work and are used, but in all 3 cases they allow you to set the context of a function before calling it. This is perfect for reusing a function that needs to know about the context in which it’s running. Just because a function is not a method on an object doesn’t mean that it can only have the global context.

## [Context When Using `new`](#context-when-using-new)

There is one situation when a function is called outside the context of an object and has its own context. And that’s if, in conjunction with calling the function, you use the `new` keyword. Let’s look at an example:

```js
function Person() {
  this.name = 'Preston';
}
```

We’ve demonstrated that calling this `Person()` function would result in `this` referring to the global `Window` object and in strict mode we’d get an error for trying to access an attribute of `undefined`. But, if we call it using the `new` keyword, `this` is not undefined and it doesn’t refer to the global `Window`:

```js
const me = new Person();
console.log(me); // { name: 'Preston' }
```

This is a less often used part of JavaScript, at least in my experience, but is important to know. When you’re trying to determine the context of a function, check to see if the `new` keyword is present.

## [Arrow Functions](#arrow-functions)

Arrow functions were introduced to JavaScript in ES6. You’ve probably seen them being used. They’re really handy and convenient. But their context is different than a normal function’s context. The rules that we looked at above do not apply to arrow functions. Let’s look at an example.

```js
const person = {
  name: 'Preston',
  sayHello: () => {
    console.log(this); // Window
    console.log(`Hello ${this.name}!`); // Hello !
  },
};
person.sayHello();
```

At first glance, we might think that the context of the arrow function will be the `person` object. I mean, `person` _is_ to the left of the dot, which is to the left of the function. But context in arrow functions works differently. The context in arrow functions inherits the context of the enclosing context. If there is no enclosing context, the context defaults to the global context (again, unless we’re in strict mode). In this example, the `sayHello` function being an arrow function means that it inherits the enclosing context. The object doesn’t have context itself, so the arrow function can’t inherit from there which means it has to inherit from the global context.

Even though arrow functions don’t have the context of the object where they’re invoked, they can still be really handy. Let’s look at an example:

```js
const spouse = {
  name: 'Amanda',
  pets: ['Tiger', 'Midnight'],
  printPets: function printPets() {
    console.log(
      this.pets.reduce(dog => {
        return `${this.name} has ${this.pets.length} ${
          this.pets.length === 1 ? 'pet' : 'pets'
        }: ${this.pets.join(', ')}.`;
       }, ''),
     );
  },
};
spouse.printPets(); // Amanda has 2 pets: Tiger, Midnight.

const person = {
  name: 'Preston',
  pets: ['Duke', 'Max'],
  printPets: function printPets() {
    console.log(
      this.pets.reduce(function(dog) {
        return `${this.name} has ${this.pets.length} ${
          this.pets.length === 1 ? 'pet' : 'pets'
        }: ${this.pets.join(', ')}.`;
      }, ''),
    );
  },
};
person.printPets(); // cannot read property 'length' of undefined
```

Each of these two objects has a `printPets` function. The purpose is to print out the number of the pets and their names. The `printPets` function is a named function, so its context is set to the object that’s calling the function, `spouse` and `person` respectively. Inside the `printPets` function, we use the `reduce` method on the `pets` array to create the string that we’ll print out. Inside the reduce method we access the `length` property of the array and use the `join` method.

The `spouse.printPets()` method works perfectly! The message `Amanda has 2 pets: Tiger, Midnight` is printed to the console. But the `person.printPets()` function call causes an error. Now why is that? The answer is in how we are using the `reduce` method. On the `spouse` object we’re using an arrow function for the `reduce` method. This means that the `reduce` method doesn’t have its own context and by default it inherits the enclosing context. That means its context is the same as the `printPets` function whose context refers to the `spouse`object.

In contrast, the `reduce` method on the `person` object uses an anonymous function and not an arrow function. That gives the `reduce` method its own context. Because it’s not called invoked by an object, its context is the global context which doesn’t have a `pets` attribute on it, and thus we get the error.

This is an example of when using an arrow function is preferred over using a named or anonymous function.

## [Conclusion](#conclusion)

The `this` keyword in JavaScript can be an overwhelming topic. It can be hard to understand what it is, or why it matters, or how to determine what it is. I’ve been working with JavaScript for about 6 years full time now, and am only barely starting to understand it. But once you get the hang of it it becomes easier to determine. And if you can look at a function and determine what `this` is referring to, you have less of a chance of introducing bugs into your code by misusing it. Hopefully this article cleared some of this up for you. If you’d like to read more, check out these articles, all of which were references for me while writing the article.

## [References](#references)

- [The many faces of `this` in JavaScript](https://blog.pragmatists.com/the-many-faces-of-this-in-javascript-5f8be40df52e)
- [Understand JavaScript`this` Keyword (Context)](https://towardsdatascience.com/javascript-context-this-keyword-9a78a19d5786)
- [Understanding Scope and Context in JavaScript](http://ryanmorr.com/understanding-scope-and-context-in-javascript/)
- [Understanding the “this” keyword, call, apply, and bind in JavaScript](https://tylermcginnis.com/this-keyword-call-apply-bind-javascript/)