DEV Community

azmy60
azmy60

Posted on • Edited on

JavaScript .call() .apply() .bind() simplified.

These three methods are part of the Function.prototypes. Basically, what they do is change the reference of this so it points to the "object target".

const sayHi = function() {
  console.log(`Hi ${this.name}!`);
};

const person = {
  name: "foxy",
};

sayHi.call(person);   // Hi foxy!
sayHi.apply(person);  // Hi foxy!
sayHi.bind(person)(); // Hi foxy!
Enter fullscreen mode Exit fullscreen mode

In this example, the 3 methods are referencing the person object so this.name is now person.name. And notice that the object reference is passed as the first argument.


.call()

Takes 1 or more arguments. The 2nd argument onward will be passed to the function.

const addItems = function(item1, item2){
  this.items.push(item1, item2);
};

const cart = {
  items: [],
};

// Add items to cart
addItems.call(cart, 'lettuce', 'watermelon');
Enter fullscreen mode Exit fullscreen mode

p.s. we can use arguments instead of item1, item2:

const addItems = function(){
  this.items.push(...arguments);
};
Enter fullscreen mode Exit fullscreen mode

.apply()

Takes 1 or 2 arguments. The 2nd argument must be an array.

addItems.apply(cart, ['egg fried rice', 'cucumber']);
Enter fullscreen mode Exit fullscreen mode

.bind()

Takes only 1 argument. In contrast with the above methods, this method will not call the function at once. It returns a new function instead, so you have to call it later manually.

// Make a new function
const boundAddItems = addItems.bind(cart);

// Call it here
boundAddItems('milk', 'jellybeans', 'more jellybeans');

// Or pass it to another function
document.querySelector('button')
  .addEventListener('click', boundAddItems)
Enter fullscreen mode Exit fullscreen mode

Bonus example

Let's say we want to add an event listener to the entire <button> in a document. We can use .querySelectorAll() to retrieve the buttons, which will return a NodeList. A NodeList doesn't contain functions like .map() or .forEach(). But we can borrow these functions from Array.prototype and use it like this:

const buttons = document.querySelectorAll('button');
Array.prototype.forEach
  .call(buttons, (el) => el.addEventListener('keydown', ...))
Enter fullscreen mode Exit fullscreen mode

In javascript, Array is just an object. And so NodeList! Therefore, using the prototype methods of Array with an object is fine, as long as it is an array-like object.

A NodeList contains a collection of incrementing numbers, and a length property, which is why it is similar to an Array.

Thanks for reading!

Links:

Function.prototypes.call() | MDN

Function.prototypes.apply() | MDN

Function.prototypes.bind() | MDN

NodeList | MDN

Top comments (0)