bind
function returns a new function with its context (this) set to a given value. It prepends the arguments given to it to the arguments which are passed when calling the new function. It is defined on the prototype of Function class.
Function.prototype.bind
Syntax
bind(thisArg, arg1, …, argN)
- thisArg – Value to be used as context (this) when calling the new function. As per MDN, if it is not provided then the execution scope will be used as thisArg for the new function.
- arg1, …, argN – Optional – Arguments which will be prepended before the arguments passed in the new function.
Examples
const starWars = {
master: 'Obi-Wan Kenobi',
disciple: 'Anakin Skywalker'
};
function printDetails() {
console.log(`${this.master} trained ${this.disciple}`);
}
printDetails();
const boundedPrintDetails = printDetails.bind(starWars);
boundedPrintDetails();
undefined trained undefined Obi-Wan Kenobi trained Anakin Skywalker
const permanentTeam = {
dev1: 'Mike',
dev2: 'Ae-Cha',
engineeringManager: 'William'
};
function printTeamDetails(...contractDevs) {
console.log(`
Permanent Members:
Dev 1 - ${this.dev1}
Dev 2 - ${this.dev2}
Engineering Manager - ${this.engineeringManager}
Contract Developers - ${contractDevs.join(', ')}
`);
}
printTeamDetails('Alice', 'Adele');
printTeamDetails.bind(permanentTeam, 'Angela', 'Edith')('Alice', 'Adele');
Permanent Members: Dev 1 - undefined Dev 2 - undefined Engineering Manager - undefined Contract Developers - Alice, Adele Permanent Members: Dev 1 - Mike Dev 2 - Ae-Cha Engineering Manager - William Contract Developers - Angela, Edith, Alice, Adele
Can we write our own “bind” function?
Let’s see if we can have our own implementation of “bind” function.
Function.prototype.myBind = function (thisArg, ...bindArgs) {
if (thisArg === null || thisArg === undefined) {
throw new Error('this not provided');
}
const originalFunction = this;
const newFunction = function (...funcArgs) {
const newContext = Object.create(thisArg);
const allArgs = bindArgs.concat(funcArgs);
newContext[originalFunction.name] = originalFunction;
return newContext[originalFunction.name](...allArgs);
}
return newFunction;
}
Let’s use the above example only to test out our implementation.
const permanentTeam = {
dev1: 'Mike',
dev2: 'Ae-Cha',
engineeringManager: 'William'
};
function printTeamDetails(...contractDevs) {
console.log(`
Permanent Members:
Dev 1 - ${this.dev1}
Dev 2 - ${this.dev2}
Engineering Manager - ${this.engineeringManager}
Contract Developers - ${contractDevs.join(', ')}
`);
}
printTeamDetails('Alice', 'Adele');
printTeamDetails.myBind(permanentTeam, 'Angela', 'Edith')('Alice', 'Adele');
Permanent Members: Dev 1 - undefined Dev 2 - undefined Engineering Manager - undefined Contract Developers - Alice, Adele Permanent Members: Dev 1 - Mike Dev 2 - Ae-Cha Engineering Manager - William Contract Developers - Angela, Edith, Alice, Adele
Though we were able to create our own “bind” function, it should be noted that the above code is nowhere near to the original “bind” function and should be used only for learning purposes.
Explanation
- Define a new function on prototype of Function class. We are doing this because we want our function to be available on all functions rather taking them as argument.
- Check if thisArg is provided, throw an error if not. Original
bind
function, however, do not throw an error. We have added this for our simplicity only. - Store the reference to the calling function (this) in a new variable.
- Create a new function which
- Creates a new object with its prototype set to thisArg. Why? Because we don’t want to make the original context (thisArg) dirty.
- Concatenates the arguments given in
myBind
and the new function. - Adds the original function as a property to the new object.
- Executes the original function on the new object and return the result.
- Return the new function.