Quiz

Explain `Function.prototype.bind` in JavaScript

Topics
JavaScriptOOP
Edit on GitHub

TL;DR

Function.prototype.bind is a method in JavaScript that allows you to create a new function with a specific this value and optional initial arguments. It's primary purpose is to:

  • Binding this value to preserve context: The primary purpose of bind is to bind the this value of a function to a specific object. When you call func.bind(thisArg), it creates a new function with the same body as func, but with this permanently bound to thisArg.
  • Partial application of arguments: bind also allows you to pre-specify arguments for the new function. Any arguments passed to bind after thisArg will be prepended to the arguments list when the new function is called.
  • Method borrowing: bind allows you to borrow methods from one object and apply them to another object, even if they were not originally designed to work with that object.

The bind method is particularly useful in scenarios where you need to ensure that a function is called with a specific this context, such as in event handlers, callbacks, or method borrowing.


Function.prototype.bind

Function.prototype.bind allows you to create a new function with a specific this context and, optionally, preset arguments. bind() is most useful for preserving the value of this in methods of classes that you want to pass into other functions.

bind was frequently used on legacy React class component methods which were not defined using arrow functions.

const john = {
age: 42,
getAge: function () {
return this.age;
},
};
console.log(john.getAge()); // 42
const unboundGetAge = john.getAge;
console.log(unboundGetAge()); // undefined
const boundGetAge = john.getAge.bind(john);
console.log(boundGetAge()); // 42
const mary = { age: 21 };
const boundGetAgeMary = john.getAge.bind(mary);
console.log(boundGetAgeMary()); // 21

In the example above, when the getAge method is called without a calling object (as unboundGetAge), the value is undefined because the value of this within getAge() becomes the global object. boundGetAge() has its this bound to john, hence it is able to obtain the age of john.

We can even use getAge on another object which is not john! boundGetAgeMary returns the age of mary.

Use cases

Here are some common scenarios where bind is frequently used:

Preserving context and fixing the this value in callbacks

When you pass a function as a callback, the this value inside the function can be unpredictable because it is determined by the execution context. Using bind() helps ensure that the correct this value is maintained.

class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
},
};
const john = new Person('John Doe');
// Without bind(), `this` inside the callback will be the global object
setTimeout(john.greet, 1000); // Output: "Hello, my name is undefined"
// Using bind() to fix the `this` value
setTimeout(john.greet.bind(john), 2000); // Output: "Hello, my name is John Doe"

You can also use arrow functions to define class methods for this purpose instead of using bind. Arrow functions have the this value bound to its lexical context.

class Person {
constructor(name) {
this.name = name;
}
greet = () => {
console.log(`Hello, my name is ${this.name}`);
};
}
const john = new Person('John Doe');
setTimeout(john.greet, 1000); // Output: "Hello, my name is John Doe"

Partial application of functions (currying)

bind can be used to create a new function with some arguments pre-set. This is known as partial application or currying.

function multiply(a, b) {
return a * b;
}
// Using bind() to create a new function with some arguments pre-set
const multiplyBy5 = multiply.bind(null, 5);
console.log(multiplyBy5(3)); // Output: 15

Method borrowing

bind allows you to borrow methods from one object and apply them to another object, even if they were not originally designed to work with that object. This can be handy when you need to reuse functionality across different objects

const person = {
name: 'John',
greet: function () {
console.log(`Hello, ${this.name}!`);
},
};
const greetPerson = person.greet.bind({ name: 'Alice' });
greetPerson(); // Output: Hello, Alice!

Practice

Try implementing your own Function.prototype.bind() method on GreatFrontEnd.

Further Reading

Edit on GitHub