Is "this" really that complicated in JavaScript?
Tags: javascript, oop, webdev
Published: 2021-04-19 15:03:31

`this` keyword can be one of the most confusing monsters in JavaScript. Especially those who didn't learn JavaScript as their first programming language find it pretty confusing as it behaves differently in JS compared to the other languages. And many programmers rely on libraries like jQuery, so they learn how to use it but don't get to fully comprehend its fundamentals. Well, let me show you how `this` isn't as confusing as you think.

---

## What is "this" in JavaScript?

[MDN Web Doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) explains that `this` is:
> **A property of an execution context** (global, function or eval) that, in non–strict mode, is always a reference to an object and in strict mode can be any value. In most cases, **the value of `this` is determined by how a function is called** (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called.


To put it simply, **`this` is a keyword used to reference the execution context.** We could think of it as "whoever it is that calls the function." So `this` typically refers to the object that is invoking its method. In JavaScript, any value can be determined when it is defined or when the function is called. The latter is the case for `this` keyword usually in the case of **Implicit binding**.

With **Implicit binding**, the value of `this` is determined based on the execution context. But `this` behaves differently if the function being invoked as an **arrow function** or if you are using [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) introduced in ES5.  And there's **Explicit binding** which you can explicitly bind `this` keyword to an object you pass as an argument for `call()`, `bind()`, and `apply()` methods. Let's dive in deeper to each of them.

---

### 1. Object Method

Take a look at the following code:

```javascript
  var hi = {
    myName: 'Slim Shady',
    myNameIs: function() {
      console.log(this.myName);
    }
  }

  hi.myNameIs();  // prints 'Slim Shady'
```

The above code's `hi` object has a method `myNameIs` which logs `myName` of `this` in the console. When `hi` object invokes its method like the following `hi.myNameIs()`, the object who called the function is `hi` which makes `this` to be implicitly bound to `hi` object. Hence, the console will log `myName` of the object `'Slim Shady'`. A simple way to look at it is that **whatever is on the left side of a dot notation of a method being invoked is the object that `this` will be referring to.** 

How about this example though:

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

  whatIsThis(); // prints Window {...}
```
Hmm... we just discussed that an easy way to understand `this` keyword in object method invocation is paying attention to the left side of dot notation. But this time, `whatIsThis` is a function defined using function declaration, and we can execute it without an object which logs `this` as the `window` object.

Sounds pretty confusing right? Well, when we declare a function, we are making it a global function available to the global object, so the function's containing scope is the global object `Window`. Another way to execute `whatIsThis` is: `window.whatIsThis()`. Look at that, `window` is on the left side of `whatIsThis()`! This brings me to the next point -- `this` in global context.

---

### 2. Global Context

As we discussed, when a method inside an object is executed by the object, `this` refers to the object. But what happens if I try to simply log `this` into console? Give it a try in your browser.

``` javascript
  console.log(this); // prints Window {...}
```
Looks like `this` refers to `window` object. By default, `this` refers to the global object (Window in browser environment). If we want to understand why it is, ask yourself (or Google) what the `window` object is. If we take a look at [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Glossary/Global_object) again, it explains:

> The window object is the Global Object in the Browser. **Any Global Variables or Functions can be accessed as properties of the window object.**

When we add `this` to your browser console, your global environment Window is executing the expression `this`, so the window object is being referred to in this global context. 

Back to the Slim Shady example, here's a function created using the `myNameIs` method in `hi` object earlier:

```javascript
  var hi = {
    myName: 'Slim Shady',
    myNameIs: function() {
      console.log(this.myName);
    }
  }

  var hisNameIs = hi.myNameIs;

  hisNameIs(); // prints undefined
```
Interesting. `hisNameIs` function logged `undefined` in the console. Let's try to understand what happened at the line `var hisNameIs = hi.myNameIs`. 

First, `hi.myNameIs` is a method -- a property containing a function definition. We simply declared a **global function** named `hisNameIs` by using `var` and initialized it with the function definition from `hi` object passed.

Second, global functions are stored as properties in the `window` object. When we invoke the global function `hisNameIs()`, it is the same as `window.hisNameIs()`. The window is the object that is executing its method `hisNameIs`, so `this` is now referring to the `window` object. window object does not have a property named `myName`, so it will return undefined.

In conclusion, **`this` will refer to the global object in global context.**

---

### 3. Strict Mode

JavaScript was first introduced in 1995 as *Mocha* which took 10 days to develop by a Netscape programmer named **Brandon Eich**. It would be surprising if the language came out to be perfect in 10 days of development right? The language has evolved to today's version 6 (ES6), with the language designers' attempt to correct the flaws in the past versions. Its legacy features were not possible to be removed in order to maintain the backward compatibility, which is why *strict mode* was introduced in ES5 to opt in to correct the early language flaws. 

`this` keyword is one of them. It behaves differently when you opt into *strict mode*:

``` javascript
  function whatIsThis() {
    "use strict";
    console.log(this);
  }

  whatIsThis(); // prints undefined
```
In *strict mode*, `this` keyword will default to undefined in function invocation. It is likely that `this` keyword was not meant to point to the `window` object, as you can simply use `window` keyword to do so.

In ES5, `bind()` method was introduced to explicitly set the function's `this` regardless of how it is called. You can pass an object as an argument when using `bind()` method, and the function's `this` keyword will refer to the object no matter how the function is invoked. Bringing back the code from earlier using `bind()` method this time, we can now create a new function with object passed explicitly like this:

``` javascript
  var hi = {
    myName: 'Slim Shady',
    myNameIs: function() {
      "use strict"
      console.log(this.myName);
    }
  }

  var hisNameIs = hi.myNameIs.bind(hi)

  hisNameIs(); // prints Slim Shady
```
Boom! Even with the strict mode, `hisNameIs` function's `this` will refer to the `hi` object passed no matter what. `call()` and `apply()` are basically the same which you can pass additional arguments to the function. The three methods are slightly different which you can read more about in this [blog post](https://medium.com/@omergoldberg/javascript-call-apply-and-bind-e5c27301f7bb).

---

### 4. Arrow function

`this` inside an **arrow function** behaves a bit differently compared to the one inside a function declaration or a function expression. Arrow function was introduced in ES6 as an alternative to a traditional way of defining function. Let's compare these two objects using the different versions of function:

``` javascript
// using regular function as callback inside forEach()
var oldPhone = {
    owner: 'Chuck',
    apps: ['Facebook', 'YouTube', 'Uber'],
    useApps: function () {
        this.apps.forEach(function(app) {
            console.log(this.owner + ' is using ' + app)
                        // this refers to the window object
        })
    }
}

oldPhone.useApps()
// prints undefined is using Facebook
// prints undefined is using YouTube
// prints undefined is using Uber

```

`oldphone.useApps` function iterates each of the `apps` using `forEach` with a regular function passed as a callback function. However, the callback function inside `forEach` method does not bind to the original object. Instead, it will bind to the global `window` object thus `this.owner` returns `undefined`. 

This could be very inconvenient if we were doing something similar as a `class`. There are two ways to fix it though, `forEach()` method takes an optional argument `thisArg` in addition to the callback function like this: `arr.forEach(callback[, thisArg])`.

Or we can use an **arrow function** as a callback to utilize its *lexical scoping*:

``` javascript
// using arrow function as callback inside forEach()
var newPhone = {
    owner: 'Chuck',
    apps: ['Facebook', 'YouTube', 'Uber'],
    useApps: function () {
        this.apps.forEach((app) => {
            console.log(this.owner + ' is using ' + app)
        })
    }
}

newPhone.useApps()
// prints Chuck is using Facebook
// prints Chuck is using YouTube
// prints Chuck is using Uber
```
Voila! This time the callback function's `this` referred to `newPhone`, and logged `this.owner` as `'Chuck'`. Arrow function allows you to write functions in a cleaner way, and they have **lexical scope** I mentioned earlier which means that they will inherit the scope from its parent. 

The callback function nested inside the `forEach` method above inherited the scope from its parent `useApps` which is `newPhone` object. Because of this nature, **The value of `this` inside an arrow function is determined when that arrow function is defined** unlike the typical situations from earlier. I personally think that `this` inside an arrow function is the most confusing part of `this` keyword, but it simply inherits the scope from its parent.

> **NOTE**
`bind()`, `call()`, and `apply()` are not compatible with arrow functions. Arrow functions will inherit the scope from its parent regardless.


---

## Conclusion

To conclude, let's summarize how `this` works in JavaScript:
- `this` is a keyword used to reference the execution context
- In **method invocation**, the object that is invoking the method would be the execution context `this` will refer to
- In global context like regular function invocation, `this` will default to the global object
- In *strict mode*, `this` keyword will default to undefined in regular function invocation.
- You can use `bind()`, `call()`, or `apply()` to explicitly bind an object to a function
- An arrow function will inherit the scope from its parent, so `this` inside an arrow function will follow its parent's `this`
- `bind()`, `call()`, and `apply()` do not work for arrow functions

Hope this was a helpful resource for you to understand how `this` works in JavaScript. Feel free to comment below if you have any questions or notice any inaccurate information and I will respond as soon as possible :)

Follow me on Clubhouse @chuckchoiboi