# call vs apply vs bind

Source: https://tpiros.dev/blog/call-vs-apply-vs-bind

The `call()`, `apply()` and `bind()` methods in JavaScript let us change the value of the `this` keyword.

> What the `this` keyword is, is something we will discuss at a later article especially focussing on how it's different from `that` and `self`.

# `call`
The `call()` method takes a function belonging to one object and fires it for a different object. This matters because of how the `this` keyword behaves in JavaScript. (We'll cover `this` in a separate article, but the short version: `this` ties to the object where a given function was invoked from.)

Here's an example:

```javascript
// creates a "constructor" for a Person object
function Person(name, age) {
  this.name = name;
  this.age = age;
}
// creates a "constructor" for a Student object
function Student(department) {
  this.department = department;
};
```

The question: how do we create a new Student instance that has a name and an age? (The idea being that a Student is also a Person.) In JavaScript, `this` always references the object where the function was invoked from. So we need a way to call one function within the other and attach it to a different object, along with its `this` value:

```javascript
// creates a "constructor" for a Person object
function Person(name, age) {
  this.name = name;
  this.age = age;
}
// creates a "constructor" for a Student object
function Student(name, age, department) {
  Person.call(this, name, age);
  this.department = department;
};

const student = new Student('John', 19, 'Software Engineering');
console.log(student.name); // John
```

# `apply`
The `apply()` method lets us invoke a function and pass arguments to it as an array.

The use-case: situations where we'd call a function multiple times but want to assign a different `this` object each time. Note that `apply` and `call` are very similar. The difference: `call` takes an argument list (as we saw above: `Person.call(this, name, age)`) while `apply` takes an array.

```javascript
const users = [
  {
    name: 'John',
    department: 'IT',
  },
  {
    name: 'Susan',
    department: 'Product',
  },
];

// accessing this.name is only possible because of apply used later
function greet(greeting, emoji) {
  console.log(`${greeting}, ${this.name} ${emoji}`);
}
const greetings = ['hi', 'hola', 'ciao', 'yo', 'aloha'];
const emojis = ['😊', '👋', '✋', '🙋'];
users.forEach((user) => {
  // greet every user with different messages, randomly
  greet.apply(user, [
    greetings[Math.floor(Math.random() * greetings.length)],
    emojis[Math.floor(Math.random() * emojis.length)],
  ]);
});
```

Another example (borrowed from MDN) shows a great use-case. Imagine you have an array with a few elements, and another array with more elements. Using `push` to add one array to the other gives you an array inside an array:

```javascript
const nums = [0, 1];
const moreNums = [2, 3];
nums.push(moreNums);
console.log(nums); // [ 0, 1, [ 2, 3 ] ]
```

You might reach for `concat`, but that creates a new array rather than appending to the original:

```javascript
const nums = [0, 1];
const moreNums = [2, 3];
const newNums = nums.concat(moreNums);
console.log(nums); // [0, 1]
console.log(newNums); // [ 0, 1, 2, 3 ]
```

That could be the desired outcome. But if you want to append elements to the _original_ array, `apply()` does the job:

```javascript
const nums = [0, 1];
const moreNums = [2, 3];
nums.push.apply(nums, moreNums);
console.log(nums); // [0, 1, 2, 3]
```

# `bind()`

Ever heard of "exotic function objects"? It's a real thing in JavaScript (introduced as part of [ES2015](https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-es6/b3c7f001-1111-1111-a005-d4a700cc1a13)). With `bind()`, we create a new bound function (an exotic function object) that wraps the original function object. Calling this newly created function executes the function it wrapped.

Why is this useful? It lets us "remember" the value of `this`. The value of `this` gets decided at runtime (runtime binding), which can cause unexpected behaviour. See the example below:

```javascript
const obj = {
  results: [],
  numbers: [1, 2, 3, 4, 5, 6, 7],
  divisible: function (num) {
    this.numbers.map(function (number) {
      if (number % num === 0) {
        this.results.push(number);
      }
    });
    return this.results;
  },
};

console.log(obj.divisible(2)); // TypeError: Cannot read properties of undefined (reading 'push')
```

The above looks perfectly fine but won't work. The `function` passed as a callback to `map()` gets attached to the `global` scope, so `this` points to the global object (in a browser, `window`). You can verify this by adding `console.log(this)` just before the `if` statement.

The fix: bind `this` to the callback block.

> Please note that ES2015 has introduced  arrow functions (`=>`) and using that will also fix the problem at hand.

```javascript
const obj = {
  results: [],
  numbers: [1, 2, 3, 4, 5, 6, 7],
  divisible: function (num) {
    this.numbers.map(
      function (number) {
        if (number % num === 0) {
          this.results.push(number);
        }
      }.bind(this)
    );
    return this.results;
  },
};

console.log(obj.divisible(2));
```

You can run all these examples below.

<p class="codepen" data-height="300" data-theme-id="default" data-default-tab="js" data-slug-hash="oNGXOWo" data-editable="true" data-user="Cloudinary" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/team/Cloudinary/pen/oNGXOWo">
  call-apply-bind</a> by Cloudinary (<a href="https://codepen.io/team/Cloudinary">@Cloudinary</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
