Understanding call(), apply(), and bind() in JavaScript

JavaScript is a versatile language with powerful features that can sometimes be confusing, especially for newcomers. Three such features are call(), apply(), and bind(). These methods are used to control the context (this value) of a function, which is essential for writing flexible and maintainable code.

What is this in JavaScript?

Before diving into call(), apply(), and bind(), it's crucial to understand what this refers to in JavaScript. The value of this is determined by how a function is called. It can refer to different objects depending on the call context:

  • In a method, this refers to the owner object.
  • Alone, this refers to the global object (in non-strict mode) or undefined (in strict mode).
  • In a function, this refers to the global object (in non-strict mode) or undefined (in strict mode).
  • In an event, this refers to the element that received the event.
  • this can be explicitly set using call(), apply(), or bind().

For more on this topic, check out my other article on Understanding this in JavaScript

The call() Method

The call() method calls a function with a given this value and arguments provided individually. It allows for method borrowing, enabling one object to use a method from another object.

Syntax

function.call(thisArg, arg1, arg2, ...)
  • thisArg: The value to use as this when calling the function.
  • arg1, arg2, ...: Arguments for the function.

Example

const person = {
  firstName: 'John',
  lastName: 'Doe',
  fullName: function () {
    return `${this.firstName} ${this.lastName}`
  },
}

const anotherPerson = {
  firstName: 'Jane',
  lastName: 'Smith',
}

console.log(person.fullName.call(anotherPerson)) // Jane Smith

In this example, we borrowed the fullName method from the person object and called it on anotherPerson using call(). The this value inside fullName refers to anotherPerson.

The apply() Method

The apply() method is similar to call(), but it accepts arguments as an array or an array-like object. This is useful when you have an array of arguments and want to pass them to a function.

Syntax

function.apply(thisArg, [argsArray])
  • thisArg: The value to use as this when calling the function.
  • [argsArray]: An array or array-like object containing the arguments.

Example

const numbers = [1, 2, 3, 4, 5]

function sum(a, b, c, d, e) {
  return a + b + c + d + e
}

console.log(sum.apply(null, numbers)) // 15

In this example, we used apply() to pass the elements of the numbers array as arguments to the sum function.

The bind() Method

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. Unlike call() and apply(), bind() does not immediately call the function; it returns a new function.

Syntax

const boundFunction = function.bind(thisArg, arg1, arg2, ...)
  • thisArg: The value to use as this when calling the new function.
  • arg1, arg2, ...: Arguments to prepend to arguments provided to the bound function.

Example

const module = {
  x: 42,
  getX: function () {
    return this.x
  },
}

const retrieveX = module.getX
console.log(retrieveX()) // undefined

const boundGetX = retrieveX.bind(module)
console.log(boundGetX()) // 42

In this example, we used bind() to create a new function boundGetX with this set to module. When boundGetX is called, it correctly returns the value of module.x.

Differences Between call(), apply(), and bind()

While call(), apply(), and bind() are used to set the this value of a function, they have distinct differences:

  • Immediate Invocation: call() and apply() invoke the function immediately, while bind() returns a new function that can be invoked later.
  • Arguments: call() accepts arguments individually, whereas apply() accepts arguments as an array. bind() allows partial application, where you can set some arguments initially and provide the rest later.

Summary Table

MethodInvocationArguments
call()ImmediateIndividually
apply()ImmediateAs an array
bind()LaterIndividually or partially

Use Cases

Understanding when to use each method is crucial for effective JavaScript programming:

  • Method Borrowing: Use call() or apply() to borrow methods from other objects.
  • Passing Arguments as Arrays: Use apply() when you have an array of arguments.
  • Function Binding: Use bind() to create a new function with a specific this value, useful for event handlers and callbacks.

Method Borrowing Example

const car = {
  brand: 'Toyota',
  getBrand: function () {
    return this.brand
  },
}

const bike = {
  brand: 'Yamaha',
}

console.log(car.getBrand.call(bike)) // Yamaha

Passing Arguments as Arrays Example

function greet(greeting, name) {
  return `${greeting}, ${name}!`
}

const args = ['Hello', 'Alice']
console.log(greet.apply(null, args)) // Hello, Alice!

Function Binding Example

const user = {
  name: 'Alice',
  greet: function (greeting) {
    console.log(`${greeting}, ${this.name}`)
  },
}

const greetUser = user.greet.bind(user)
greetUser('Hi') // Hi, Alice

Conclusion

In JavaScript, controlling the context (this value) of a function is essential for writing flexible and maintainable code. The call(), apply(), and bind() methods provide powerful ways to manipulate this and pass arguments to functions. By understanding their differences and use cases, you can leverage these methods to write more effective JavaScript code.