Do you really know JavaScript ? Part 2: Call, Apply And Bind
Tags: javascript, webdev, beginners, codenewbie
Published: 2021-04-20 16:52:20

Call, apply and bind methods are used to set the `this` value, independent of how the function is called. We can use the method of an object with another object, without worrying about where the `this` keyword will be pointing. 

#### Call Method

The `call` method help us to call a method of a object from another object and it sets value for the `this` keyword if we provide one, the function is executed immediately. Call method takes parameters for the function as comma separated values.

```javascript
functionName.call(thisVal, arg1....argN);
```
1. `thisVal` represent the value `this` should be using when the function is invoked.
2. `arg1....argN` represents the list of argument that will be passed to the function as parameters.  

```javascript
let obj1 = {
    fname : "kiran",
    lname : "raj",
    display() { console.log(`${this.fname} ${this.lname}`) }
};

obj1.display();     // kiran raj
```
In the above code `obj1` has two properties(`fname`, `lname`) and one method (`display`), the method simply console the `fname` and `lname` properties of the object which is pointed by the `this` keyword. When we invoke the method by calling `obj1.display()`, we get a console output "kiran raj", here the `this` keyword inside the method points towards the object before the dot that cause the invocation, here obj1 is before the dot and `this` will point towards obj1. So `this.fname` become `kiran` and `this.lname` become `raj`. This is how JavaScript normally works.

Let's try to access the display method from another object.

```javascript
let obj1 = {
    fname : "kiran",
    lname : "raj",
    display() { console.log(`${this.fname} ${this.lname}`)}
}

let obj2 = { fname : "Vishnu", lname : "R",}
obj2.display()
//Uncaught TypeError: obj2.display is not a function
```
I tried to call display method with `obj2` but I got an error, so there is no ways to call display from another object?

There are certain ways, lets me show one of those ways, using call method.

```javascript
let obj1 = {
    fname : "kiran",
    lname : "raj",
    display() { console.log(`${this.fname} ${this.lname}`)}
}

let obj2 = { fname : "Vishnu", lname : "R",}

obj1.display.call(obj2);    //Vishnu R
```
Yay, we were able to call the display method from another object, the surprise is not ending there, look at the result, it prints the properties of `obj2` not `obj1`. what it means? It means that  `this` keyword is now pointing towards obj2.

So we can say that call method help us to invoke a method belonging to an object using another object. Call method also provide a new value to `this` of the method. Call method accept arguments that can be passed as parameters to the method as comma separated values. 

Lets look at another example
```javascript
let obj1 = {
    count : 0,
    increaseCount() {
        this.count++;
        console.log(this.count);
    }
}

let obj2 = { count:100 };
        
obj1.increaseCount();            // 1
obj1.increaseCount();            // 2
obj1.increaseCount.call(obj2);   // 101
obj1.increaseCount.call(obj2);   // 102
```
Finally one more example, try it and find the output.
```javascript
function Car(type, company, yr){
   this.yr = yr;
   this.company = company;
   this.type = type;
}

function Sedan(type, company, yr){
    Car.call(this, type, company, yr);
    this.sedan = true;
}

function printDetails(){
    console.log(`${this.type}`);
    console.log(`${this.company}`);
    console.log(`${this.yr}`);
    if(this.sedan){console.log("Sedan");}
}
let myCar = new Sedan('Petrol', 'Hyundai', 2019);
printDetails.call(myCar);
```

#### Apply Method

`Apply` method is same as `call` method the only difference is, apply method accept parameters for the function to which it is attached as argument array. 

```javascript
functionName.apply(thisVal, [argArray]);
```
Let's look at an example 
```javascript

let obj1 = {
    fn : "kiran",
    ln : "raj",
    display(fn, ln) {console.log(`${this.fn} ${this.ln}`)}
}

let obj2 = {fn : "Vishnu",ln : "R",}
obj1.display.apply(obj2);   //Vishnu R

let obj3 = {
    fn: "arun",
    ln: "v.i.",
    getDetails(age, place){
       console.log(`${this.fn} ${this.ln}`);
       console.log(`${age} : ${place}`);
    }
};


obj3.getDetails.apply(obj1, [33, 'venjaramoodu']);
// kiran raj 33 : venjaramoodu

obj3.getDetails.apply(obj2, [33, 'venjaramoodu']);
// Vishnu R 33 : venjaramoodu
```
Compare the code with that of the `call` method, the only difference you will find will be the `argArray`, which contains all the parameters for the function to which the `apply` method is attached.

One more example
```javascript
function Car(type, company, yr){
    this.yr = yr;
    this.company = company;
    this.type = type;
}
function Sedan([type, company, yr]){
    Car.apply(this, [type, company, yr]);
    this.sedan = true;
}
function printDetails(){
    console.log(`${this.type}`);
    console.log(`${this.company}`);
    console.log(`${this.yr}`);
    if(this.sedan){
        console.log("Sedan");
    }
}

let myCar = new Sedan(['Petrol', 'Hyundai', 2019]);
printDetails.call(myCar);
```

Let me summarize, Apply method is used to call a method/function of an object with another object, `apply` method can assign a user assigned value to `this` keyword, the function is immediately invoked.

#### Bind Method

"The bind() function creates a new bound function, which is an exotic function object that wraps the original function object. Calling the bound function generally results in the execution of its wrapped function." : MDN Docs

Unlike call or apply function bind function creates a new function, a bound function. 

```javascript
let boundFuntion = functionName.bind(thisVal, arg1.....argN)
```
1. `thisVal` is the value that will be set to the `this` keyword.
2. arg1......argN argument values for the original function.

```javascript
let obj3 = {
    fname : "kiran",
    lname : "raj",
    display(title) {
        console.log(`${title}.${this.fname} ${this.lname}`)
    }
}

obj3.display("Mr");                         // Mr.kiran raj
```

I will try to explain the above code snippet, we create an object, obj3, which have two properties "fname" and "lname" and a method display. The display method simply logs to the console fname and lname of `this`, with a title which it get as parameter. We invoke the method,`obj3.display("Mr");` and got a output "Mr.kiran raj" as the `fname` and `lname` value of `this` is "kiran" and "raj" respectively. 

Let's create another object which contain 'fname' and 'lname' as properties, can we call the display method from obj4?, Let's try

```javascript
let obj3 = {
    fname : "kiran",
    lname : "raj",
    display(title) {
        console.log(${title}.${this.fname} ${this.lname})
    }
}

let obj4 = {fname:"Vishnu", lname: "R"};
obj4.display("Mr");
// Uncaught TypeError: obj4.display is not a function

```   
No we cannot call display from another object, if we do, it will throw an TypeError. Let's use bind method to call display from another object.

```javascript
let obj3 = {
    fname : "kiran",
    lname : "raj",
    display(title) {
       console.log(`${title}.${this.fname} ${this.lname}`)
    }
}
let obj4 = {fname:"Vishnu", lname: "R"};
let boundFn = obj3.display.bind(obj4);
boundFn("MR");                               // MR.Vishnu R

let obj5 = {fname:"Arun", lname: "V.I."};
obj3.display.bind(obj5)("Mr");              // Mr.Arun V.I.
```
Yay, worked!, we create a bound function `boundFn`, assign the value of `obj3.display.bind(obj4)` to it, then invoke the bound function to get the result, "MR.Vishnu R". We can directly call without assigning the bound function to a variable, which is shown in the last line of the example.

Bind function is used to call a method/function of an object using another object, the bind function is not invoked immediately, bind function create a new bound function, which needed to be invoked to get the result. 

Let's try one more example.

```javascript
let myName = {
    fn: "kiran",
    ln: "raj",
    printName(){console.log(`${this.fn} ${this.ln}`);}
}

setTimeout(myName.printName, 1000);
//undefined undefined

setTimeout(myName.printName.bind(myName), 1000);
//kiran raj
```
when passing a method to the setTimeout function, this points towards the global object, here windows. In the global object there is no `fname`or `lname`, so we get undefined, then we bind the `this` to `myName` and this points towards `myName` and we get the output as "kiran raj".

Call, apply and bind help to access a method of object from another method and helps to assign new value to `this`.

If the article have shortcomings or mistakes please point, your feedback is highly appreciated. Happy coding :) 

[Do you really know JavaScript ? Part 1 : Undefined](https://dev.to/kiranrajvjd/do-you-really-know-javascript-part-1-undefined-1pda)