What Is “this”, After All? — A Look at JavaScript’s this Keyword
Tags: javascript, webdev, frontend, tutorial
Published: 2020-09-17 05:20:55

[![Originally published at webtips.dev](https://dev-to-uploads.s3.amazonaws.com/i/6irb941wofatfbenpcf2.png)](https://www.webtips.dev/javascript-this-keyword)

What is this all about? This doesn’t even make any sense… Where is this coming from? — Everyone asked these questions to themselves at some point in their lives, so let’s settle the argument and demystify this once and for all. If you haven’t figured it out yet, this story is going to be about the dreaded `this` keyword in JavaScript.

First, let’s define what `this` is.

> *The “this” keyword in JavaScript refers to the object it belongs to.*

Open up your console and write *“this”*. In this case *“this”* alone in itself refers to the **global object**. The global object in a browser is the window itself.

![The global object in the browser](https://miro.medium.com/max/700/1*tsk3Y4lLRL0AxNSjzDDGew.png)

---

## First Example

Now, what if we have our own object? What do you think the output will be in the following case?

```javascript
const user = {
    name: 'Heisenberg',
    occupation: 'entrepreneur',
    sayMyName() {
        console.log(this.name);
    }
};

const sayMyName = user.sayMyName;

sayMyName();
```

If you guessed “Heisenberg”, you were wrong. You would actually get an empty string. But why is that? What would happen if you were to just call `user.sayMyName()` right away? — It would log out **Heisenberg**. Wait… WHAT??? 😨 Let’s start with the latter before I manage to confuse you even more.

We said that the keyword refers to the object it belongs to. When you call `user.sayMyName()`, this will point to the `user` object, hence when you call `this.name`, sure enough, you get back “Heisenberg”.

So what happens when you assign `user.sayMyName` to a new variable like we did in the example above? — Simply put, `user.sayMyName` becomes a plain function, completely unrelated to the `user` object.

Try to copy the example above to your DevTools and instead of calling `sayMyName()` write `console.log(user.sayMyName)` to log out the function itself. You would get back the exact function we defined in the `user` object. However, this time, the parent object of the function becomes the window.

And by the alignment of the stars, we do have a `name` property on the window, but by default, it’s value reads “” — an empty string. If we were to change `this.name` to `this.userName`, you would get `undefined`, because there’s no `window.userName` by default.

### How do we fix this?

So we know we don’t get back the expected output because we are referring to the wrong object. Okay, that’s cool, but how do we fix it? Well, you simply bind the context, which you can do with the `bind` method. Change line:9 to the following:

```javascript
const sayMyName = user.sayMyName.bind(user);
```

Bind expects a parameter that sets the `this` keyword to the provided value’s context. In this case, we want to bind the context to the `user` object so we pass “user”.

What if you want to use the function in a callback? — Same as before, you only need to bind the context, like we did before, and pass the extracted function as a callback:

```javascript
document.getElementById('say-my-name').addEventListener('click', sayMyName);
```

## Second Example

Let’s see two more examples. By now, it’s starting to become suspicious whether it will give back the expected value or not. In any case, you’re sitting in an interview and the interviewer writes down a coding exercise on the whiteboard with an evil smile when you suddenly get the question you are anticipating —

> “What do you think the output will be for the following?”

```javascript
const shape = {
    radius: 10,
    diameter() {
        return this.radius * 2;
    },
    perimeter: () => 2 * Math.PI * this.radius
};

shape.diameter();
shape.perimeter();
```

![Sweating all over the place](https://miro.medium.com/max/500/1*r7WLartsCRT6PmlmaOQwFg.gif)

Of course, they can’t expect you to calculate all this in your head right? — You’re thinking… There must be a catch. There is! Let’s break it down.

First, you call `shape.diameter`, everything seems to be fine, we return the object’s radius * 2. Nothing fancy is going here, you get back 20. Next, you call `shape.perimeter`, you get back `NaN` 🤦‍♂️.

Comparing the two methods, it must have something to do with the way they are written. And you are right. The second one is an arrow function. Arrow functions don’t bind their own context, rather they are referring to the enclosing scope in which the object is defined, which is again, the window. And `window.radius` is evaluated to `undefined`. So the above function evaluates to `2 * 3.14 * undefined` which in return, gives us `NaN`.

*Note that for one-liners in arrow function, you can omit the `return` keyword. The above example is equivalent to this:*

```javascript
perimeter: () => {
    return 2 * Math.PI * this.radius;
};
```

---

## Third Example

Let’s see a last one, this time going back to the very first example with a little twist, because why not.

Imagine you’re investigating a bug and you suspect that the root cause is related to a piece of code where you have an object with a method. You also have an enclosing inner function inside said method for some reason.

```javascript
const user = {
    name: 'Heisenberg',
    occupation: 'entrepreneur',
    sayMyName() {
        const closure = function() {
            console.log(this.name);
        };

        return closure();
    }
};

const sayMyName = user.sayMyName;

sayMyName();
```

You quickly realize that this is not what it’s supposed to be. You want this to work, you want `this` to point to your object, but again nothing seems to work, you get an empty string. Seems like it is pointing to the window once more.

*Can’t we just `delete window` to solve all our problems?*

Just like for the previous one, you have a great idea!💡 Bind the `user` object to the assigned function!

```javascript
const sayMyName = user.sayMyName.bind(user);
```

But you are still getting `""`. Unfortunately, that’s only half of the equation. To understand why, we need to pick it apart. If we are logging out `sayMyName` again, you get the body of the function which returns the inner function at line:9. If you insert `console.log(closure)` to line:8, you'll see that we get back the closure’s body with the `console.log` inside.

We know that we are getting back an empty string because `this` is pointing to the window object, so we must bind the right context to `closure`, right? That’s right, so you go ahead and return `closure.bind(this)` instead, but this time, you are getting back the body of the function 🤔.

That’s because `bind` only does the binding, but doesn’t actually call the function which we need. So you say we only need to do either

```javascript
return closure.bind(this)();
```

*or*

```javascript
user.sayMyName()();
```

As you probably already guessed, this is kind of a workaround and looks hacky and is not really the proper solution. We have another method that can be used to call a specific function with a given context. It’s the `call` method.

By changing the return to `return closure.call(this)`, you tell JavaScript to call the function with the given context passed as a parameter. So that leaves us with the final solution being:

```javascript
const user = {
    name: 'Heisenberg',
    occupation: 'entrepreneur',
    sayMyName() {
        const closure = function() {
  	    console.log(this.name);
        };
  
  	return closure.call(this)
    }
};

const sayMyName = user.sayMyName.bind(user);

sayMyName();
```

You first bind the `user` object to your function assignment on line:13 and inside `sayMyName`, you also have to use call on the closure function to call it with the proper context.

As you can see, `this` works according to some rules which after you start to understand, everything else will make more sense… hopefully.

---

## Things to Keep in Mind

- By default `this` refers to the **global object**, which is the `window` if you are in a browser.
- When you use `this` inside another object, it refers to the object it belongs to.
- When `this` is used inside an arrow function, it refers to the parent object.
- If you use a function call with `bind` or `call`, `this` will refer to the context passed as the first parameter to these methods. *(`bind` will only bind the context while `call` will call the function as well.)*

---

[![Learn more about JavaScript and web development](https://dev-to-uploads.s3.amazonaws.com/i/hiwy3jv9ipkcallv33gf.png)](https://www.webtips.dev/)