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

Every JavaScript function has three methods inherited from Function.prototype: call(), apply(), and bind(). These methods allow you to explicitly set the value of 'this' when calling a function, enabling method borrowing and partial application.

Function.call()

The call() method invokes a function with a specified 'this' value and arguments provided individually. It immediately executes the function.

Using call()
const person = {
  fullName: function(city, country) {
    return this.firstName + ' ' + this.lastName + ', ' + city + ', ' + country;
  }
};

const person1 = { firstName: 'Alice', lastName: 'Smith' };
const person2 = { firstName: 'Bob', lastName: 'Jones' };

// call(thisArg, arg1, arg2, ...)
console.log(person.fullName.call(person1, 'NYC', 'USA'));
console.log(person.fullName.call(person2, 'London', 'UK'));

Function.apply()

The apply() method is similar to call(), but takes arguments as an array (or array-like object) instead of individually. It also immediately executes the function.

Using apply()
const person = {
  fullName: function(city, country) {
    return this.firstName + ' ' + this.lastName + ', ' + city + ', ' + country;
  }
};

const person1 = { firstName: 'Alice', lastName: 'Smith' };

// apply(thisArg, [argsArray])
console.log(person.fullName.apply(person1, ['NYC', 'USA']));

// Useful with Math methods
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
const min = Math.min.apply(null, numbers);
console.log('Max: ' + max);
console.log('Min: ' + min);

// Modern alternative with spread:
console.log('Max (spread): ' + Math.max(...numbers));

Function.bind()

The bind() method creates a new function with a fixed 'this' value. Unlike call() and apply(), bind() does NOT immediately execute the function. It returns a new function that can be called later.

Using bind()
const user = {
  name: 'Alice',
  greet: function() {
    return 'Hello, I am ' + this.name;
  }
};

// Without bind: 'this' is lost
const greetFunc = user.greet;
// greetFunc() would have 'this' as undefined in strict mode

// With bind: 'this' is permanently set
const boundGreet = user.greet.bind(user);
console.log(boundGreet());

// bind with different object
const admin = { name: 'Bob (Admin)' };
const adminGreet = user.greet.bind(admin);
console.log(adminGreet());

Setting 'this' Explicitly

All three methods let you control what 'this' refers to inside a function. This is crucial when methods are passed as callbacks or used in different contexts.

MethodExecutes immediately?ArgumentsReturns
call()YesIndividual argsFunction result
apply()YesArray of argsFunction result
bind()NoIndividual args (partial)New function
Comparing call, apply, bind
function introduce(greeting, punctuation) {
  return greeting + ', I am ' + this.name + punctuation;
}

const person = { name: 'Alice' };

// call - immediate, individual args
console.log(introduce.call(person, 'Hi', '!'));

// apply - immediate, array of args
console.log(introduce.apply(person, ['Hey', '!!']));

// bind - returns new function
const boundIntro = introduce.bind(person, 'Hello');
console.log(boundIntro('...'));
console.log(boundIntro('!!!'));

Borrowing Methods

You can borrow methods from one object and use them on another. This is especially useful for array-like objects that don't have array methods.

Method Borrowing
// Borrowing array methods for array-like objects
function listArguments() {
  // 'arguments' is array-like but not an array
  const args = Array.prototype.slice.call(arguments);
  console.log('Args: ' + args.join(', '));
}

listArguments('a', 'b', 'c');

// Borrowing methods between objects
const calculator = {
  value: 0,
  add: function(n) { this.value += n; return this; },
  getValue: function() { return this.value; }
};

const myObj = { value: 10 };
calculator.add.call(myObj, 5);
console.log('Borrowed result: ' + calculator.getValue.call(myObj));

Partial Application with bind()

bind() can pre-fill some arguments of a function, creating a new function with fewer parameters. This is called partial application.

Partial Application
function multiply(a, b) {
  return a * b;
}

// Create specialized functions using partial application
const double = multiply.bind(null, 2);
const triple = multiply.bind(null, 3);
const times10 = multiply.bind(null, 10);

console.log('double(5): ' + double(5));
console.log('triple(5): ' + triple(5));
console.log('times10(5): ' + times10(5));

// Practical example: logging with prefix
function log(level, message) {
  console.log('[' + level + '] ' + message);
}

const info = log.bind(null, 'INFO');
const error = log.bind(null, 'ERROR');

info('Server started');
error('Connection lost');
📝 Note: Arrow functions do not have their own 'this', so call(), apply(), and bind() cannot change the 'this' value of arrow functions. The 'this' in an arrow function is always inherited from the enclosing lexical scope.
Exercise:
What is the difference between call() and bind()?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.