# Call(), Apply() & Bind() functions in Javascript.

- These functions are usually used when we want to set the `this` keyword independent of how the function is being called in our code.

Lets understand this in a clear way with an example. Assume a flight company minimal object, it stores the 

- `name of the flight`
- the `iata code`(location identifier code)
- the `bookings` array and
- has a method `book` that books the flight using the flight name and the name of the passenger as the arguments.

```jsx
const airIndia = {
	airline: 'Air India',
	iataCode: 'AI3',
	bookings: [],
	book(flightNum, name) {
		console.log(`${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`);
		this.bookings.push({ flight: `${this.iataCode}${flightNum}`, name });
	}
}
```

Now, to book a flight we can simply call the book method and pass in the passenger name and the flightNumber.

```jsx
airIndia.book(111, 'RahulK');
airIndia.book(112, 'devtuber');

// Output: 
// RahulK booked a seat on Air India flight AI3111
// devtuber booked a seat on Air India flight AI3112
```

Up until here, there was nothing to do with the call, apply and bind functions. But, now lets take it to the next step. Lets assume that AirIndia opens up a new subsidiary airline 'flyer'.

The object should have similar properties as to airIndia. 

```jsx
const flyer = {
	airline: 'Flyer',
	iataCode: 'FF3',
	bookings: [],
  book(flightNum, name) {
		console.log(`${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`);
		this.bookings.push({ flight: `${this.iataCode}${flightNum}`, name });
	}
}

// It will use the book method from the parent airline(AirIndia).
```

So, here we would exploit the DRY principle if we re-wrote the book() method within the flyer object. How can we improve this?

### What happens when we try to use the book() from AirIndia object?

```jsx
const bookTicket = airIndia.book;
bookTicket(24, 'Rahul'); // error
```

- this will certainly give an error because when we store the book() method into the bookTicket, bookTicket no longer remains the method rather becomes the normal function whose this keyword points to undefined.
    
    ### Things to remember:
    
    - `this` always refers to an object.
    - `this` refers to an object which calls the function it contains.
    - In the `global` context `this` refers either to the `window` object or is `undefined` if the strict mode is on.

### How to solve this?

- One way is to create a book function explicitly that takes in three arguments: `airline object`, `passenger name`, `flight number` and books the flight for any airline.
- Second way is to set the value of `this` using either the call(), apply() or bind() methods while calling book() from AirIndia.

### Using Call(thisArg, ...parameters)

`The call() method sets the 'this' inside the function and immediately executes that function.`

- Syntax: function.call(thisArg, param1, param2...)

So, now instead of passing only the parameters asked in the bookTicket(), we can also pass the object to which the `this` should reference to using the call().

```jsx
const bookTicket = airIndia.book;
bookTicket.call(flyer, 24, 'Rahul');

// Output: Rahul booked a seat on Flyer flight FF224
```

### Using Apply(thisArg, [param1, param2...])

Apply() method works similar to call(), it also `sets the 'this' inside the function and immediately executes that function.` Only difference is that it takes the arguments in the form of an array.

```jsx
const bookTicket = airIndia.book;
bookTicket.apply(flyer, [24, 'Keyboard']);

// Output: Keyboard booked a seat on Flyer flight FF224
```

### Using Bind(thisArg, optionalArguments)

Bind() actually works similar to call() and apply() but has some differences. The main difference is that `bind() method creates a new function that, when called, has its this keyword set to the provided value.`

```jsx
const bookBind = airIndia.book.bind(flyer);
bookBind(24, 'Rahul');

// Output: Rahul booked a seat on Flyer flight FF224
```

Optionally, we can always provide the other arguments as well within the bind() method. We are allowed to pass in partial arguments too. Let make it clear through an example.

```jsx
const bookBind = airIndia.book.bind(flyer, 25);
bookBind('Rahul');

// Output: Rahul booked a seat on Flyer flight FF225
```

In the above code, we have optionally passed the flight number and not the name within the bind() method, which is perfectly fine.

```jsx
const bookBind = airIndia.book.bind(flyer, 25, 'Rahul');
bookBind();

// Output: Rahul booked a seat on Flyer flight FF225
```

In the above code, we have passed both the flight number and the name within the bind() method, which is perfectly fine too.
