The call, apply, and bind methods exist to change the execution context of a function, specifically to alter the binding of the this keyword within the function.
The core difference is that call and apply invoke the function immediately with the new context, while bind returns a new function with the context permanently bound, ready for later execution.
The bind() Method
This method creates a new function (a bound function). When invoked, its this keyword is set to the provided value. Any arguments pased to bind are prepended to the arguments provided when the bound function is finally called.
Syntax: function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg: The value to be passed as thethisparameter to the target funcsion when the bound function is called. This value is ignored if the bound function is constructed using thenewoperator.arg1, arg2, ...: Arguments to prepend to arguments provided to the bound function when it is invoked.
Example: Changing this Context
const globalName = "globalName";
const user = {
userName: "objectName",
getName: function() { return this.userName; }
};
console.log(user.getName()); // "objectName" - `this` refers to `user`
const unboundGetName = user.getName;
console.log(unboundGetName()); // "globalName" - `this` refers to the global object/window
// Use bind to set the context
const boundGetName = unboundGetName.bind(user);
console.log(boundGetName()); // "objectName" - `this` is now bound to `user`
Application: Function Currying with bind
bind can be used to create a function with preset initial arguments.
function listArgs() {
return Array.from(arguments); // Convert arguments to an array
}
const boundList = listArgs.bind(null, 'first', 'second');
console.log(boundList()); // ['first', 'second']
console.log(boundList('third', 'fourth')); // ['first', 'second', 'third', 'fourth']
The call() and apply() Methods
Both methods immediately invoke a function with a specified this value.
call(): Accepts thethiscontext followed by an individual list of arguments.apply(): Accepts thethiscontext followed by a single array of arguments.
Syntax Comparison:
func.call(context, arg1, arg2, arg3);
func.apply(context, [arg1, arg2, arg3]);
Practical Applications
1. Converting Array-like Objects to True Arrays
Objects with a length property and indexed elements (like arguments or NodeList) can be converted using Array methods.
const arrayLike = {
0: 'itemA',
1: 'itemB',
2: 'itemC',
length: 3
};
const trueArray = Array.prototype.slice.call(arrayLike);
console.log(trueArray); // ['itemA', 'itemB', 'itemC']
Note: An object without a length property will resultt in an empty array.
2. Merging Arrays
Use apply to push elements from one array into another.
const primary = [10, 20, 30];
const secondary = [40, 50];
Array.prototype.push.apply(primary, secondary);
console.log(primary); // [10, 20, 30, 40, 50]
3. Determining Data Type
A reliable method to check an object's type is to use Object.prototype.toString.call().
function checkType(value) {
return Object.prototype.toString.call(value);
}
console.log(checkType([])); // "[object Array]"
console.log(checkType(null)); // "[object Null]"
console.log(checkType('text')); // "[object String]"
4. Implementing Constructor Inheritance
call or apply can be used within a child constructor to inherit properties from a parent constructor.
function Animal(name) {
this.name = name;
}
function Cat(name) {
// Inherit Animal's properties in the context of the new Cat instance
Animal.call(this, name);
}
function Dog(name) {
// Same using apply
Animal.apply(this, arguments);
}
const kitty = new Cat('Whiskers');
const puppy = new Dog('Rex');
console.log(kitty.name); // 'Whiskers'
console.log(puppy.name); // 'Rex'