Crack 'this' concept of Javascript.
Tags: javascript, this, functional, objectorientedjs
Published: 2021-06-11 15:36:33

# Introduction

Javascript in itself is a mixture of functional programming paradigm and object oriented programming paradigm. *this* is one of the fundamental ingredients of object oriented programming.

*this* is one of the built-in parameters in javascript which is implicity available inside a javascript function. *this* is passed a value by the javascript engine, behind the scenes, when the function is called. For example, it contains a reference to the object on which the function is invoked. That is why, It is also called function context.

# This and Function Invocation

That was a brief introduction to *this*. Lets get into nitty gritty of how can we crack the value of *this* which is the main goal of this article.

Value of *this* parameter inside a function depends on the manner in which the function is invoked. Yes, there are different ways to invoke/call a function in javascript.

__We can invoke a function in javascript in 4 ways:__
* _As a function_- 
```javascript
assemble() /* assume that *assemble* is a simple javascript function*/
```
* _As a method_-
```javascript
avengers.assemble() /*This ties the function call to an object 
enabling OOPS. This is also called calling a function on an 
object.*/ 
```
* _As a constructor_-
```javascript
new Avenger() /* This is how you create new objects in 
javascript: preceding function call with 'new'.*/
```
* _Via the function's apply/call methods_-
```javascript
smash.call(hulk); // smash is a function here.;
smash.apply(hulk);
```
Lets start discussing them one by one with the help of examples.

**Invocation as a function:**

```javascript
// all ways to invoke a function as a function.
function assemble(){
    console.log(this); //outputs window object
}
assemble();

let assemble = function(){
    console.log(this); // outputs window object
}
assemble();

(function(){
    console.log(this); // outputs window object
})();

```
In each case we will observe that console outputs a *window* object. Hence, when function is invoked as a function *this* parameter inside the function starts referring to _window_ object which is inbuilt javascript global object in browser. However if we run our code in strict mode *this* in such a case becomes undefined.
```javascript
function assemble(){
    'use strict';
    console.log(this); //outputs undefined
}
```


**Invocation as a method:**

When a function is assigned to a property of an object, it becomes a method.
``` javascript
let avengers = {
    assemble:function(){
        console.log(this); //outputs avengers object
    }
};
avengers.assemble(); // assemble is called upon avangers.
```
In this example, *assemble* is a method of *avengers* object. We observe that *this* parameter inside *assemble* function holds a reference to the *avengers* object when *assemble* is called upon *avengers* object. This gives us a sense of how OOPS is being implemented in javascript. 

*this* parameter inside a function will point to the object in which the function is defined if the function is called upon that object. When a function is called upon an object in which it is defined, we say that the function has been invoked as a method.


**Invocation as a constructor:**

A simple function in javascript becomes a constructor when it is invoked in a specific way in javascript. Lets dive straight into code to know this specific way.

```javascript
function Avenger(name,weapon){
    this.name = name;
    this.weapon = weapon;
}
let Thor = new Avenger('Thor','Mjolnir');
``` 
See here *Avenger* itself is a simple javascript function. When it is invoked, it is preceded by an inbuilt javascript keyword *new*. This type of invocation converts our simple function into a constructor. So we say, we invoked our function as a constructor.

When any function is invoked as a constructor, three things happen:

* a new empty javascript object is created in memory.
* Inside the constructor(*Avenger* function), *this* parameter starts referring to this newly created object.
* After the execution of constructor finishes, the newly constructed object is returned as *new* operator's value even though no return statement is there in constructor. Therefore, *Thor* variable starts referrring to our new object as shown in figure below.

![jsobject](jsobject.drawio.png)

**Invocation with apply and call methods:**

We know, in javascript, functions are first class objects. Therefore, properties can be assigned to them. *call* and *apply* are built-in methods available on any function in javascript. Both functions work in almost similar way.

Lets now dive straight into code again to understand mechanism of *this* here.
```javascript

function setQuality(...args){
    this.qualities = args;
}
let Thor = {name : 'Thor'};
let Captain = {name : 'Steve'};
setQuality.call(Captain,'diligent','persistent','motivated');

setQuality.apply(Thor,['loyal','heroic','bold'])

console.log(Thor.qualities); // outputs ['loyal','heroic','bold']
console.log(Captain.qualities); // outputs ['diligent','persistent','motivated']
```
In above example, we have function *setQuality*. This function takes a list of arguments which is represented by *args* parameter. It is a special parameter called as *rest* parameter. You can read more about rest parameter [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). For the time being, consider *args* to be a pure javascript array which contains all arguments sent to the function.

Now, when *setQuality.call* method is invoked, *setQuality* itself is invoked. First argument to *setQuality.call* will become the value of *this* parameter inside *setQuality*. Rest of the arguments passed to *setQuality.call* are the arguments with which *setQuality* is invoked and will go inside array represented by *args* parameter of *setQuality*.

Similarly, when *setQuality.apply* method is invoked, *setQuality* itself is invoked. First argument to *setQuality.apply* will become the value of *this* parameter inside *setQuality*. Second argument to *setQuality.apply* is an array. Values inside this array just represent the arguments with which *setQuality* is invoked and will go inside array represented by *args* parameter of *setQuality*.

You can read more about *call* method [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call).
You can read more about *apply* method [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply).

# *this* in Event Handlers

To understand how the value of *this* parameter is decided inside a function which acts as an event handler, let's take an example:
```javascript
<button id='demo'>Click!</button>
<script>
    function Avenger(name,weapon){
        this.name = name;
        this.weapon = weapon;
        this.maxHealth = 100;
        this.displayMaxHealth = function(){
            console.log(this.maxHealth);// outputs undefined.
        }
    }
    let Thor = new Avenger('Thor','Mjolnir');
    let btn = document.getElementById('demo');
    btn.addEventListener('click',Thor.displayMaxHealth);
</script>
```
It is a little surprising that instead of *100*, *undefined* is output on console when we click the button. The reason behind this goes like this.

Inside the addEventListener method we passed a reference to our *displayMaxHealth* method which is defined inside *Avenger* function. *displayMaxHealth*(event handler) will be called by the event handling system of the browser when we click the button inside the DOM with id 'demo'. Therefore, value of *this* which will be passed to this function at the time of its invocation is also decided by the event handling system of the browser. It sets *this* to the button element instead of *Thor* object. 
Since button object does not have any variable with name *maxHealth*, therefore *undefined* is output on the console.

Therefore, *this* parameter in case of event handlers refers to DOM element that was the target of the event and is handled by event handling system of browser.

Now if we want to output the correct value of *100*, Javascript provides us with some ways. 

One of the ways can be to use the built-in *bind* method. This method, like *apply* and *call*, is defined on every function in javascript. This method, when called on a function, creates and returns a new function. This new function has some special characteristics.
1. The new function has the same body as the function on which bind was called. 
2. Also, the value of *this* parameter inside the new function will always be bound to the value passed as first argument to bind method, regardless of the manner in which we now invoke the new function.

This will become clear when we modify above example.

```javascript
<button id='demo'>Click!</button>
<script>
    function Avenger(name,weapon){
        this.name = name;
        this.weapon = weapon;
        this.maxHealth = 100;
        this.displayMaxHealth = function(){
            console.log(this.maxHealth);// outputs 100
        }
    }
    let Thor = new Avenger('Thor','Mjolnir');
    let btn = document.getElementById('demo');
    btn.addEventListener('click',Thor.displayMaxHealth.bind(Thor));
</script>
```
The second way can be to use the arrow functions. This is because value of *this* parameter in case of arrow functions is decided in a specific way which I am going to discuss in the next section. 


# *this* in Arrow functions.


Arrow function was introduced in ES6 and is really a cool feature in javascript.

Arrow functions don't have their own *this* value which means javascript engine does not pass a value to the *this* parameter of arrow functions at the time of their invocation. Then, how is the value of 
*this* decided?

The value of *this* parameter in case of arrow functions is decided at the time of their declaration. Value of *this* is decided by the context in which arrow functions are declared. This will become clear with examples.

```javascript
function Avenger(name,weapon){
    this.name = name;
    this.weapon = weapon;
    this.maxHealth = 100;
    this.reduceHealth = () =>{
        this.maxHealth-=Math.floor(((Math.random())*100)+1);
    }
}
let Thor = new Avenger('Thor','Mjolnir');
Thor.reduceHealth();
console.log(Thor.maxHealth);// will output a numeric value.
```
*reduceHealth* function is an arrow function declared inside constructor function *Avenger*. So, we say *reduceHealth* is declared inside the context of *Avenger* function. Since *Avenger* is a function, it's context is called a functional context. Inside *Avenger* function, value of *this* refers to a newly constructed object. Now, we can say that value of *this* parameter inside *Avenger* function is passed on to *this* parameter inside *reduceHealth* function as shown in above example.

Let's take another example.
```javascript
let Captain ={
    name:'Steve',
    weapon:'Shield',
    maxHealth:100,
    displayMaxHealth : () =>{
       console.log(this.maxHealth);
    }
}
Captain.displayMaxHealth(); // console outputs undefined.
```
Why did console output 'undefined' in this example? This is because of the way value of *this* parameter is determined inside an arrow function. 

In this example, *displayMaxHealth* is a method on *Captain* object. Unlike previous example, it is not declared inside a functional context. *Captain* object itself is declared inside global context i.e. outside of all functions. Therefore, *displayMaxHealth* method, declared inside *Captain* object, is said to be declared inside a global context.

**Note: global context, global level(outside all functions) are synonymous terms.**

What is the value of *this* inside global context? Lets see.
```javascript
console.log(this); //this outputs global 'window' object.
```
Therefore, since *displayMaxHealth* is lying inside global context and value of *this* inside global context is *window* object, hence value of *this* parameter inside global context is passed on to the *this* parameter inside *displayMaxHealth* function.

Now, *this* inside *displayMaxHealth* points to *window* object and the *window* object does not contain any variable with the name *maxHealth*. This explains why we got *undefined* in the output in above example.

**Note: Inside global context, if we are using strict mode, value of *this* will be undefined.**

# Conclusion

*this* concept is one of the most fundamental and important concepts in Javascript. Sometimes it becomes a bit tricky to grasp the nitty gritty of the concept. However, once you fully understand this concept, it is going to help you a lot in the long run.

Hopefully these explanations helped you really understand the concept of *this* in JavaScript!.