this keyword in JavaScript
Tags: javascript, programming, webdev
Published: 2021-06-29 11:09:13

## Introduction
Hey everyone !
I have been recently learning `ReactJS`. While learning about class based components I stumbled across the `bind` keyword. 

```javascript
this.somefunction = this.somefunction.bind(this)
```
While trying to understand this line of code, I realized that the binding of the methods is not a React specific thing, It is a JavaScript thing .

I also realized that to understand the trio of `call, apply and bind` which basically do similar things, we need to understand the `this` keyword in JavaScript.

So, today I'd like to discuss about :
- What is `this` ?
- `this` in global scope
- `this` within an object
- `this` within a function
- `this` within classes
- The call, apply and bind methods

By learning about all these things we get to know why we bind methods in ReactJS.

Alright! let's get going.

![plane](https://user-images.githubusercontent.com/51131670/121888880-25245c00-cd36-11eb-93f8-9f810940cb4e.gif)

## So what is `this` all about ?

When we use 'this' in our daily conversations it always has a context attached with it, right? For instance, the sentence "This is my house" can only make sense in two ways when you are inside the house or you point to the house you are talking about. 

If in the middle of the street you say "This is my house" it doesn't really make sense, because 'this' isn't really pointing to anything. If you have a picture of your house then regardless of the location you can point to the picture and attach the context to 'this', it will be like 'this house(in the picture) is my house'.

 Similarly in JavaScript, `this` keyword will point to something according to the context it is in or we can point it to the thing we want using call, apply and bind . This will make better sense when we see the different contexts `this` can be defined in. 
 
--- 
## In Global Context
When we create a JavaScript file, even if there are zero lines of code written in the file a few things are created. One of the things created is the window object. The window object contains different properties and methods including things related to DOM. 

When we write the `this` keyword in a global context ( outside any kind of function ), by default it points to the `window` object.

If we create a variable like this 
```javascript
this.thing = "window thing"
```
we could access it using `this.thing` as well as `window.thing` since `this` points to the window object.
```javascript
    console.log(this.thing)
    // # "window thing"
    console.log(window.thing)
    // # "window thing"
```

---

## Strict Mode
Before we proceed to the context of a function, we need to understand strict mode.

In simple words, strict mode apply more restrictions and rules to JavaScript. Certain things would be allowed in non-strict mode but throw an error in strict mode.

We can enable strict mode using the statement `"use strict"` in the JS file .

---

## Within a function

From here onwards, things will get a little weird, so stick with me.
```javascript
function printsomething(){
    console.log(this) // Window object
}
printsomething()
```
When we call `this` in a function in non-strict mode it points to the window or the global object. In strict mode `this` is undefined and it looses the context.
```javascript
"use strict"
function printsomething(){
    console.log(this) // undefined
}
printsomething()
```

---

## Within an object

When we call the `this` keyword in an object method, `this` points to the object it was defined in. 

For Example : 
```javascript
this.name = "Some other movie"
const movie = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}

movie.print()

// OUTPUT
// Peanut Butter Falcon

```
In the above example, we define a method called `print` within the object `movie`. The object `movie` has a property called `name`.

 In `print` we call `console.log(this.name)` which would basically point to the `name` property of the `movie` object.
 
It will ***not*** print "Some other movie" since the `print` function is in the context of the object `movie`.

---

## The weird part 
Remember when I told you that the value of `this` depends on the way it was called?
Let us use the same object we used previously to understand this. 

What if we assign the method `print` to another variable called `globalprint`?

```javascript
this.name = "Rocky"
const movie = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}
const globalprint = movie.print

globalprint()
//output : Rocky

```

Now, the context of `this` has changed to the global context since `globalprint` is not a method of the `movie` object, it is an independent function as we have seen in the function section, points to the global context in `non-strict mode` and is undefined in `strict mode`.

So, the output would be `"Rocky"` instead of `"Peanut Butter Falcon"`.

![this is fine](https://user-images.githubusercontent.com/51131670/123542591-08d9e380-d768-11eb-82c3-71f3bb64fdba.gif)


---

This also applies to callback functions. 
```javascript
this.name = "Rocky"

const movie = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}
   
setTimeout(movie.print , 1000 ); // Output : Rocky
```
We can try to fake a setTimeout method to look at how this works.

```javascript
function setTimeout(callback, delay){

   //wait for 'delay' milliseconds
   callback();
   
}

setTimeout( movie.print, 1000 );
```

Internally the setTimeout method assigns the `movie.print` to it's callback argument.

```javascript
callback = movie.print
```
As we saw before, assigning a method to another variable changes it's context. Thus `print` will be "undefined" in `strict mode` and in `non-strict mode` 
it will print "Rocky".

---

## Within class methods <a name="withinClass"></a>

```javascript
class theatre {
    constructor(person,movie){
        this.person = person
        this.movie = movie
    }
    display(){
        console.log(`${this.person} is watching ${this.movie}`)
    }
}

const peter = new theatre("peter","interstellar")
const jack = new theatre("jack","inception")

jack.display()
//output : peter is watching interstellar
peter.display()
//output : jack is watching inception

```
Within a class `this` point to the current instance of the class.
Here the instances being `jack` and `peter`.

However, the class methods like `display` will lose context if passed as a callback function or assigned to another variable like we saw in the functions section.

**Class expression and methods such as the constructor or any class methods are always executed in `strict mode`.**

Thus callbacks, instead of taking the global context, will be undefined.


```javascript
const callback = jack.display
callback() // "this" will be undefined
```

We will be learning about `bind` method shortly to fix this problem. To give you an idea , `bind` will basically glue value of `this` to the display function and it will always be called in that context, fixing the problem of the context getting lost.

---
Remember the house analogy I used in the beginning?
We'll now understand the pointing at the picture of the house part, that is basically telling javascript explicitly where you want `this` keyword to point rather than JavaScript assigning it for you.

## call
`call` method is used to call a function with the `this` pointing to a thing of your choice.

### Syntax

`call(thisArg, arg1, ... , argN)`

`thisArg` helps the call function to knw on which `this` should the function be called.
Rest arguments are the arguments passed to the function.

Let's understand the use case with an example.
```javascript
const movie = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}

```
Remember this object? 
What if we create two movie objects with different movies?
```javascript
const movie1 = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}
const movie2 = {
    name : "The imitation game",
    print : function (){
        console.log(this.name) 
    }
}
``` 
We can see here the `print` function is repeated. If there were more of these
objects, we would have to write the same print function multiple times.

We could use a `call` method in this case.

We would remove the `print` method out of the objects and make it as a separate function .

```javascript
const printThings = function (){
        console.log(this.name) 
    }

const movie1 = {
    name : "Peanut Butter Falcon"   
}
const movie2 = {
    name : "The imitation game"
}
```
Now, we will use the `call` method on the `printThings` function with reference to whichever `this` value we want

```javascript
printThings.call(movie1) // output : "Peanut Butter Falcon"
printThings.call(movie2) // output : "The imitation game"
```

`printThings.call(movie1)` tells JavaScript that we want the above function's `this` to point to movie1 object and similarly for movie2.

It is as though the function is inside the object like given below.
```javascript
const movie1 = {
    name : "Peanut Butter Falcon",
    print : function (){
        console.log(this.name) 
    }
}
``` 

---

### What if there are parameters in the function, how do we pass those ?

```javascript
const printThings = function (person){
        console.log(`${person} is watching ${this.name}`) 
    }

const movie1 = {
    name : "Peanut Butter Falcon"   
}
const movie2 = {
    name : "The imitation game"
}
```
The `printThings` function now has an parameter called `person`.

So how do we use the call method and pass the arguments?

```javascript
printThings.call(movie1,"James") // output : "James is watching Peanut Butter Falcon"
printThings.call(movie2,"Peter") // output : "Peter is watching The imitation game"
```
The first argument is always the `this` argument , Rest can be passed after it like it is done in the above example.

Let's take one more example :

```javascript

const printprintThings = function (fname, lname){
        console.log(`${fname} ${lname} is watching ${this.name}`) 
    }

const movie1 = {
    name : "Peanut Butter Falcon"   
}
const movie2 = {
    name : "The imitation game"
}

printThings.call(movie1,"James","Bond") // output : "James Bond is watching Peanut Butter Falcon"
printThings.call(movie2,"Peter", "Pan") // output : "Peter Pan is watching The imitation game"

```
This example just has one more parameter than the previous one.

---

## apply
The only difference between `call` and `apply` is that `apply` method calls a function with a `this` value and arguments as an array instead of passing the arguments individually like the call method.
```javascript
apply(thisArg,argArray)
```

We could use the previous example and use apply on it instead of call.

```javascript
const printThings = function (fname, lname){
        console.log(`${fname} ${lname} is watching ${this.name}`) 
    }

const movie1 = {
    name : "Peanut Butter Falcon"   
}
const movie2 = {
    name : "The imitation game"
}

printThings.apply(movie1,["James","Bond"]) // output : "James Bond is watching Peanut Butter Falcon"
printThings.apply(movie2,["Peter", "Pan"]) // output : "Peter Pan is watching The imitation game"

```
It gives the same result.

---
## bind
 Bind is different from call and apply in the sense that bind returns a new function instead of calling the existing function immediately.

### Syntax 
```javascript
bind(thisArg, arg1, ... , argN)
```

Now, we could bind the function to a `this` value .

```javascript
    let printThings = function (fname, lname){
        console.log(`${fname} ${lname} is watching ${this.name}`) 
    }
    printThings = printThings.bind(movie1,"James","Bond")

printThings()
// output : "James Bond is watching Peanut Butter Falcon"
```
Thus we bind the printThings function to movie1 and we can call it whenever we want. 

---
Let us take one more example.
```javascript
    "use strict"
    this.movie = "Saving Private Ryan"
    const outerFunction = function(){
        const innerFunction = function (){
            console.log(this.movie)
        }
        innerFunction()
    }
    outerFunction()
```
From what we have seen, the above code won't work, right? Since the context is lost.

Let us `bind` the outerFunction and use `call` on the inner function and give them the `this` value

```javascript
    "use strict"
    this.movie = "Saving Private Ryan"
    let outerFunction = function(){
        const innerFunction = function (){
            console.log(this.movie)
        }
        innerFunction.call(this) 
        //Here "this" means the outerFunction
    }
    outerFunction = outerFunction.bind(this) 
    // Here "this" means the global context
    outerFunction()

    //Output : "Saving Private Ryan"
```
---
Finally, Let's try to fix the class which we made in the `Within a class` section. [click here to take a look at it again](#withinClass) 
```javascript
class theatre {
    constructor(person,movie){
        this.person = person
        this.movie = movie

    }
    display(){
        console.log(`${this.person} is watching ${this.movie}`)
    }
}

const jack = new theatre("jack","inception")

const callback = jack.display
callback()

```
The only thing we have to do to get this working is to bind the method `display` to the `this` value of the class.

We can do this either in the constructor 
```javascript
    class theatre {
        constructor(person,movie){
            this.person = person
            this.movie = movie
            this.display = this.display.bind(this) // Here
        }
        display(){
            console.log(`${this.person} is watching ${this.movie}`)
        }
    }

    const jack = new theatre("jack","inception")

    const callback = jack.display
    callback()
     
```

or bind it while passing it as a callback.

```javascript
setTimeout(jack.display.bind(jack),1000)

//output : jack is watching inception
```

```javascript
const callback = jack.display.bind(jack)
callback()
//output : jack is watching inception
```

---

## Arrow Functions
Arrow functions are another way to solve the binding problem.

Arrow function have something called as a "lexical scope".

What that means is that arrow function does not have it's own `this` context, it borrows the context from the parent element or the context it was defined in.

Hence, in the above example the outer function will get it's context from the global context and the inner function will get it's context from the outer function .

```javascript
"use strict"
    this.movie = "Saving Private Ryan"
    const outerFunction = () => {
        const innerFunction = () => {
            console.log(this.movie)
        }
        innerFunction()
    }
    outerFunction()
    //Output : "Saving Private Ryan"
```

---

## `bind` in ReactJS

We have already seen all the javascript specific reasons we bind a function or a method. The same applies for ReactJS.

In React we generally call a class method using an event handler like `onClick`, we pass the method we want to execute as a callback to the handler function.

That is why the value of `this` is lost .

By binding it explicitly we make sure it doesn't happen.

---
![that's all folk](https://user-images.githubusercontent.com/51131670/123542532-bdbfd080-d767-11eb-9a24-4a8ba0343605.gif)


I hope you learnt something from this blog.

Let me know in the comments if you found this helpful .

See you in the next one :)