Understanding this in JavaScript
Published: 2022-04-02 04:42:15

*The Topics covered are as follows*

* this keyword
* implicit binding 
* window binding
* explicit binding(bind, call and apply methods)
* new binding
* this in arrow functions


## Why is *this* used ?

**This** keyword is used to set the *context* with which a function is called in javascript. Say that *this* keyword decides what we should focus on when calling a function.
Note that the value of this keyword can always change depending on the circumstance and is not known until a function gets called, similar to how we don't know what the values of function parameters are until we call the function.

### *Lets understand via an example*

In the below example we see that the method inside of the object named India is using the this keyword to refer to the
properties of the object inside which the method is defined. In this case the context with which the method is called is the object India. We can understand that by looking at what lies at the left of the '.' when calling a method. This kind of binding is referred to as *implicit binding* wherein this keyword refers to the object that is to the left of the '.' when calling the method.

```javascript
const India = {
    name: "India",
    population: "1.2 billion",
    located: "South east Asia",

    info: function() {
       console.log(`${this.name} is a country with a population of 
       ${this.population} and is located in ${this.located}`);
    }
}

India.info();
```
What happens if we take the method out of the object and use it as a function instead?
What do you think will happen?

```javascript
 const info = function () {
    console.log(`${this.name} is a country with a population of 
    ${this.population} and is located in ${this.located}`);
}
info();
```

As you will see, the console outputs 
- *undefined* is a country with a population of *undefined* and is located in *undefined*.

Now we get the above output due to the fact that the context (think object) with whose reference the function is getting called does not have the necessary variables defined. Namely outside of any object, the this keyword would point to the global window object in case of the browser and the globalThis object in case you're using node.js .

We can confirm this by typing *this* in the browser console and we'll see something as follows:

```javascript
Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
```

Now since you know that the *this* is referencing the global window object let's try putting our required variables inside the 
window object

```javascript

window.name = "France",
window.population = "60.7 million",
window.located = "Western Europe"

info()
```
Now you will see that, the console outputs 
- *France* is a country with a population of *60.7 million* and is located in *Western Europe*.

We're able to access the values for our variables since we have added those values to the global object or the global context.
So what does this behaviour imply? It simply tells us that when we do not explicitly specify a context(think object of focus), the this keyword will point to or refer the global object. This object is called globalThis for node js runtime and is referred to as window object in the browser. This behaviour is what we call as *window binding*.

**NOTE** : Strict mode does not allow us to do window binding and attempting the same would throw an error as follows
```
 Uncaught TypeError: Cannot read properties of undefined 
```
This happens because in *strict mode* the value of this when not set does not default to the global object and is instead set to undefined.


## How to *change the context as per our requirement*?

### *Explicit binding* with call, apply and bind methods.

You most likely want to extract the method out as a function and just change the context as per your requirement.
How do you do this? Well, every ***function*** in javascript provides three methods to do this namely - ***call, apply and bind***. You can understand these methods as allowing you to call a function with a different context, apply a different context to a function, or bind a function to a different context.
Lets make use of each of them and see some differences in their usage.

```javascript
const Canada = {
    name: "Canada",
    population: "38 million",
    located: "North America"
}

const USA = {
    name: "USA",
    population: "302 million",
    located: "North America"
}
```
Above we have defined two objects named *Canada* and *USA*.
Lets call our ***info*** function with the context of *Canada* object.

```javascript
info.call(Canada);
```

The above invocation of the call method will print the follwing to the console
- *Canada* is a country with a population of *38 million* and is located in *North America*.

We can also specify any additional arguments along with the context 
using the below syntax. 

```javascript 
info.call(ContextObject, arg1, arg2, arg3); 
```
***apply*** is exactly similar to call and only differs in the fact that you must pass the additional arguments as an array.
    
```javascript 
info.apply(ContextObject, [arg1, arg2, arg3]) 
```

***bind*** method is very similar to call and apply in terms of its functionality with the difference being that unlike *call* and *apply*, *bind* does not call the method immediately. *bind* returns you a new function which is bound to a context or bound to the object with which it is called.

Let's see an example of bounded function below

```javascript
const boundedFunc = info.bind(USA);
boundedFunc();
```

In the above example we're binding the info function to the USA object and storing it in a variable named *boundedFunc*. If we call the *boundedFunc*, the output will be as
follows

- *USA* is a country with a population of *302 million* and is located in *North America*.

## New binding
New binding takes place when we use the *new* keyword to create new objects using a constructor function. Let's quickly take a look at an example to better understand the process.

```javascript
const Country = function(name, population, location) {
  this.name = name;
  this.population = population;
  this.location = location;
}

const switzerland = new Country("Switzerland", "8.6 million", "Western Europe");
```

When we call the above *constructor* function using the *new* keyword, the function creates a brand new object for us, adds the specified properties and returns the object. This process is called *new binding* wherein this keyword inside the constructor function points to the object created by the function.

## *this* in Arrow functions
Arrow functions do not have a this keyword of their own and the value of this in arrow function depends on what the value of this was in the lexical context of the function when it was created.

Let's take an example by typing the following in the browser console
```javascript
const Poland = {
    name: "Poland",
    population: "30.8 million",
    located: "Eastern europe",

  

    infoArrow: () => {
      console.log("this: ", this);
    },

    info: function() {
        return (() => this);
        
    }
}
```
Here in the *infoArrow* function the this keyword will point to the window object because as we said in arrow functions the value of this keyword depends on the lexical context in which the function was created.

Calling the *infoArrow* function will print the following
in the console
```javascript
this:  Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
```

Now let's try with our normal function. The value of this here can be decided in the normal way as explained previously. Our normal function returns an arrow function which in turn returns the value of this. Let's see how the value of this returned by the arrow function will differ based on the lexical context.

### *Case 1* 
Let's call the method info() and store the return value in a variable *ArrowFn*. This variable contains the arrow function (() => this). Note that while the arrow 
function get's created, the value of this in its lexical context is the Poland object and hence if we run this arrow function we will get the value of this as the Poland object.

```javascript
let ArrowFn = Poland.info();
console.log("Value of this: ", ArrowFn());
```

Above code outputs the following:
```javascript
Value of this:  {name: 'Poland', population: '30.8 million', located: 'Eastern europe', infoArrow: ƒ, info: ƒ}
```

### *Case 2*
Let's now just store a reference to our info method in a variable *fn*. Now *fn* is variable which consists our info() method. Note that we're effectively taking our info() method out of the Poland object and storing it in a variable fn as a function.

```javascript
let fn = Poland.info;
```

Now let's try calling fn() and store its return value(which is the arrow function) in a variable *Arrowfn2*. Now calling the arrow function will return the global window object because when the arrow function was created(by calling fn) due to window binding, the this will now reference the window object instead of the Poland object.

```javascript
let ArrowFn2 = fn();
console.log("value of this: ", ArrowFn2());

Console o/p
value of this:  Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
```

**Note** - *We cannot explicitly set the context of the arrow function using bind, call and apply as our first argument which sets the context/object will be ignored by the arrow function and by convention must therefore be set to null when being used with arrow functions. Another consequence of these behaviors of the arrow functions is that we cannot use it as a constructor function.*

And that's what the ***this*** is all about in ***javascript*** ! :)