Mastering the JavaScript "this" Keyword
Tags: javascript, oop
Published: 2019-11-01 17:55:17

**“this” keyword allows you to decide which object should be focal when invoking a function or a method.**

The **this** keyword is a very important concept in JavaScript, and also a particularly confusing one to both new developers and those who have experience in other programming languages. In JavaScript, **this** is a reference to an object. The object that **this** refers to can vary, implicitly based on whether it is global, on an object, or in a constructor, and can also vary explicitly based on usage of the Function prototype methods bind, call, and apply.

Five types of binding

* The ‘this’ keyword is probably one of the most misunderstood aspects of JavaScript.

* The first thing to understand regarding **this** keyword is to understand its purpose, or what it is that ‘**this**’ keyword allows us to do in JavaScript.
  * **It allows us reuse functions with different contexts**
  * **It allows us to decide which objects should be focal when invoking a function or a method.**

The first thing we need to ask when using **this** keyword is -
**Where is this function invoked?**


* Because whenever you’re trying to find out what **this** keyword is you have to look at when the function was **invoked**… not when it was defined, but specifically when it was invoked.
* We won’t know what **this** keyword is in a function until that function is invoked.


* Now that you know the first step to figuring out what the **this** keyword is referencing is to look at where the function is being invoked, what’s next? To help us with the next step, we’re going to establish 5 rules or guidelines.

**1) Implicit Binding**
**2) Explicit Binding**
**3) new Binding**
**4) Lexical Binding**
**5) window Binding**

**1. Implicit Bindind**

* Implicit Binding is the most common rule and will be found in about 80% of use cases when trying to figure out what **this** is.

Example 1:

```js
// Implicit Binding
// Left of the Dot at Call Time
var me = {
  name: 'Aakash',
  age: 22,
  sayName: function() {
    console.log(this.name);
  }
};

me.sayName(); // Aakash
```
* Implicit Binding says that in order to find the **this** keyword we look to the left of the dot of the function invocation. That’s what the **this** keyword is going to reference.

```js
me.sayName();
```
* In the code above, we see the sayName() invocation and look to the left of the dot. The **me** object is what this reference.


Example 2:

```js
// Implicit Binding
// Left of the Dot at Call Time
var sayNameMixin = function(obj){
  obj.sayName = function(){
    console.log(this.name);
  }
}

var me = {
  name: 'Aakash',
  age: 22
};

var you = {
  name: 'Shehan',
  age: 21
}

sayNameMixin(me); 
sayNameMixin(you); 
```

* When we pass both of these objects into our mixin it decorates them with a new sayName() property.
* Then when we invoke each we look to the left of the dot to see what this references.

```js
.
.
// Now it will print
me.sayName(); // Aakash
you.sayName(); // Shehan
```

Example 3:

```js
// Implicit Binding
// Left of the Dot at Call Time
var Person = function(name, age) {
  return {
    name: name,
    age: age,
    sayName: function() {
      console.log(this.name);
    }
  }
}

var jim = Person('Aakash', 22);
jim.sayName(); // Aakash
```

But what if we made this a bit more complex.:

```js
// Implicit Binding
// Left of the Dot at Call Time
var Person = function(name, age) {
  return {
    name: name,
    age: age,
    sayName: function() {
      console.log(this.name);
    },
    mother: {
      name: 'Sandhya',
      sayName: function(){
        console.log(this.name);
      }
    }
  }
}

var jim = Person('Aakash', 22);
jim.sayName(); // Aakash
jim.mother.sayName() // Sandhya
```

Once again we look to the left of the dot of the function invocation to get the object **this** refers to.

* This seems deceptively easy, and because it is very straight-forward, whenever you get into situations where you need to find out what **this** is, the very first thing you should do is look at when the function was invoked and then look to the left of that function to find out what this is referencing.


**2. Explicit Binding**

**Uses call, apply, or bind:**

**a) Example 1 - call**

* Let’s change things around so that sayName is just a function on the global scope but what we want to do is still call the function in the context of the stacey object.

```js
// Explicit Binding
// call, apply, bind
var sayName = function() {
  console.log('My name is ' + this.name);
}

var aakash = {
  name: 'Aakash',
  age: 22
}

sayName.call(aakash) // Aakash
```

* What we can do is type the function name and then use the **call** method, which is available to every function, to do just that.

* **The first argument that it takes in is the context that you want to call the function from.**

So now the **sayName** function is going to be invoked but the **this** keyword inside of sayName will now reference the aakash object.

So in this example we’re explicitly stating what the **this** keyword is when we use call. It is the very first argument we pass to **call**.


* **.call()** provides a new value of **this** to the function/method.

* With **call**, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object.
* Additional arguments to the function are passed in one by one after the first argument.


**Example 2 - call with args**

* Now if we want to pass a few more parameters to sayName we can do that.

* Let’s create an **array** and then pass the array elements to the function.

* The very first argument in **.call()** is the **context**. Every argument after that will be passed to the function.

```js
// Explicit Binding
// call, apply, bind
var sayName = function(lang1, lang2, lang3) {
  console.log(`My name is ${this.name}. I know ${lang1}, ${lang2}, ${lang3}.`);
}

var aakash = {
  name: 'Aakash',
  age: 22
}

var languages = ['JavaScript', 'CSS', 'Python'];

// sayName.call(aakash, languages[0], languages[1], languages[2]);
// You can also use "spread" operator
sayName.call(aakash, ...languages); 
```

* So, we are invoking **sayName** in the context of aakash and we are also passing along three arguments.


**Example 3 - apply :**

* Next what we could do is rather than pass in the arguments one by one, we could pass them in as an array.

```js
sayName.apply(aakash, languages);
```
* This is exactly what **.apply()** does. It allows us to pass in the arguments as an array.


**.apply(**) provides a new value of **this** to the function/method.

Instead of having to pass additional arguments one by one, you can pass them in as an array after context which is the first argument.



**Example 4 - bind :**

* The .**bind()** is almost the same thing as **.call()** except there’s one thing that’s different.

What **.bind()** will do is **return us a new function** instead of invoking the original function.

Looking at our code from before.

```js
// sayName.bind(aakash, languages[0], languages[1], languages[2]);
var newFn = sayName.bind(aakash, ...languages);
```

* Now, instead of invoking **sayName**, it’s just going to bind **this** to aakash, pass in the languages arguments, and **return a brand new function which we can call later.**

Now we can invoke the new function with **newFn()**.


**SUMMARY** 
* **call**, **apply**, and **bind** allow us to explicitly state what the **this** keyword is going to be in any given function.
* **call** and **apply** behave in the exact same way. They will immediately invoke the function.
* **call** requires additional arguments to be passed in one by one
* **apply** allows you to pass in the arguments as an array
* **bind** is the same as call except that instead of immediately invoking the function it returns a brand new function that can be invoked later



**3. New Binding**

*  Whenever you invoke a function with the **new** keyword, under the hood, the JavaScript interpretor will create a brand new object for you and call it **this**.
*  So, naturally, if a function was called with **new**, the **this** keyword is referencing that **new object** that the interpretor created.

Example:

```js
function User (name, age) {
  /*
    Under the hood, JavaScript creates a new object called `this`
    which delegates to the User's prototype on failed lookups. If a
    function is called with the new keyword, then it's this new object
    that interpretor created that the this keyword is referencing.
  */

  this.name = name
  this.age = age
}

const me = new User('Aakash', 22)
// "this" will now refer to "me" always.
```


**4. Lexical Binding**

* **Arrow function** allow you to write functions in a more concise format.
* Even more than conciseness, arrow functions have a much more intuitive approach when it comes to **this** keyword. Unlike normal functions, arrow functions don’t have their own **this**. Instead, **this** is determined lexically. That’s a fancy way of saying **this** is determined how you’d expect,

Example :

```js
const user = {
  name: 'Aakash',
  age: 22,
  languages: ['JavaScript', 'CSS', 'Python'],
  greet() {
    const hello = `Hello, my name is ${this.name} and I know`

    const langs = this.languages.reduce(function (str, lang, i) {
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }

      return `${str} ${lang},`
    }, "")

    alert(hello + langs)
  }
}
```
*  You’ll notice it’s throwing the error **Uncaught TypeError: Cannot read property 'length' of undefined.**
*  According to our error, **this.langauges** is undefined.It’s not referencing **user**.


Steps to find the **this** context:

* First, we need to look at where the function is being invoked. Wait? Where is the function being invoked? 
* The function is being passed to **.reduce** so we have no idea. 
* We never actually see the invocation of our anonymous function since JavaScript does that itself in the implementation of **.reduce**. That’s the problem. 
* We need to specify that we want the anonymous function we pass to **.reduce** to be invoked in the context of **user**. 
* That way **this.languages** will reference **user.languages**. 
* As we learned above, we can use **.bind**.

```js
const user = {
  name: 'Aakash',
  age: 22,
  languages: ['JavaScript', 'CSS', 'Python'],
  greet() {
    const hello = `Hello, my name is ${this.name} and I know`

    const langs = this.languages.reduce(function (str, lang, i) {
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }

      return `${str} ${lang},`
    }.bind(this), "")

    alert(hello + langs)
  }
}
```

* So we’ve seen how **.bind** solves the issue, but what does this have to do with arrow functions. Earlier I said that with arrow functions "**this** is determined **lexically**. That’s a fancy way of saying **this** is determined how you’d expect, following the normal variable lookup rules."
*  If we re-write the code above and do nothing but use an **anonymous arrow function** instead of an anonymous function declaration, everything “just works”.

```js
const user = {
  name: 'Aakash',
  age: 27,
  languages: ['JavaScript', 'CSS', 'Python'],
  greet() {
    const hello = `Hello, my name is ${this.name} and I know`

    const langs = this.languages.reduce((str, lang, i) => {
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }

      return `${str} ${lang},`
    }, "")

    alert(hello + langs)
  }
}
```


**5. window Binding**

Example:

```js
// window Binding
var sayAge = function() {
  console.log(this.age);
};

var me = {
  age: 22
}
```
* If we wanted to call sayAge in the context of me we’d have to do this.

```js
sayAge.call(me); 
```
* But if we don’t do this but instead just call sayAge we get undefined.
* The reason is if we invoke a function that uses the **this** keyword but doesn’t have anything to the left of the dot, it’s not using the new binding, and it’s not using call, apply, or bind, then the **this** keyword is going to default to the **window** object.
* So if we decide to add a property of age to the **window** object we will get that result back.

```js
window.age = 22

function sayAge () {
  console.log(`My age is ${this.age}`)  
}

sayAge()  // 22
```



***Binding rules recap***


The four rules in a quick recap.

**1) Implicit Binding -** look to the left of the dot at call time
**2) Explicit Binding -**  tells a function what the context of the **this** keyword is going to be using **call**, **apply**, or **bind**
**3) new Binding -**  is whenever you have a function invoked with the **new** keyword where the **this** keyword is bound to the new object being constructed
**4) lexical Binding -** **this** is determined lexically i,e **this** is determined how you’d expect, following the normal variable lookup rules.
**5) window Binding -**  if none of the previous rules apply then the **this** keyword is going to default to the **window** object unless you’re in **strict mode** in which case it will be **undefined**

 Now , you should be able to determine the value of **this** in your programs :)



If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me. Thanks !!!