Introduction to call, apply, bind
Here is a short intro on the elusive call, apply, bind in JavaScript
Function.prototype.call()
The call() method of Function instances calls
this
function with a given this value and arguments provided individually.
For example call function acts as a generic utility function, which can assign an arbitrary value as this
when calling an existing function, without first attaching the function to the object as a property.
Suppose we have an object like this.
1
2
3
4
5
6
7
const alice = {
username: "Alice",
age: 35,
sayHello: function() {
console.log(`Hello, ${this.username}`);
}
};
and another object
1
2
3
4
const bob = {
username: "Bob",
age: 40,
};
To attach sayHello()
to Bob, you can do this with the call method.
1
alice.sayHello.call(bob); // console.logs "Hello, Bob"
As more common use case is creating sayHello()
as an independent function and calling it like this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const alice = {
username: "Alice",
age: 35,
};
const bob = {
username: "Bob",
age: 40,
};
function sayHello() {
console.log(`Hello, ${this.username}`);
}
sayHello.call(alice); // console.logs "Hello, Alice"
sayHello.call(bob); // console.logs "Hello, Bob"
The function call
can also accept parameters. It’s call signature is,
1
call(thisArg[, arg1, arg2, /* …, */ argN])
Example
1
2
3
4
5
6
7
8
9
10
function logDetails(city, state) {
console.log(`Hello, ${this.username}. Age: ${this.age}. Lives in ${city}, ${state}`);
}
logDetails.call(alice, "Buffalo", "New York"); // console.logs "Hello, Alice. Age: 35. Lives in Buffalo, New York"
logDetails.call(bob, "London"); // console.logs "Hello, Bob. Age: 35. Lives in London, undefined"
// you can also pass an array with spread syntax
logDetails.call(alice, ...["Buffalo", "New York"]);
logDetails.call(bob, ...["London"]);
If the parameters are not provided, undefined will be the value.
Note: call()
won’t work while using arrow function expressions
1
2
3
4
5
6
7
8
const charlie = {
username: "Charlie",
age: 45,
};
const sayBye = () => {
console.log(`Bye, ${this.username}!`);
}
sayBye.call(charlie); // console.logs "Bye, undefined!"
Reason,
Arrow functions don’t have their own bindings to
this
,arguments
, orsuper
, and should not be used as methods. i.e., Inside arrow function expressions this will be the window object
1 2 3 4 5 6 const sayBye = () => { console.log(this === window); // true } const sayBye = function() { console.log(this === window); // false }
*** Function.prototype.apply()
This function is almost identical to
call()
, except that the function arguments are passed tocall()
individually as a list, while forapply()
they are combined in one object, typically an array — for example,func.call(this, "eat", "bananas")
vs.func.apply(this, ["eat", "bananas"])
.
The function apply
can also accept parameters. It’s call signature is,
1
apply(thisArg[, argsArray])
A example would be,
1
2
3
4
5
6
7
8
9
10
11
12
13
const func = function(action, fruit) {
console.log(`${this.animalType} ${action} ${fruit}.`);
};
const monkeys = {
animalType: 'Monkeys',
getFood: function() {
func.apply(this, ["eat", "bananas"]);
// func.call(this, "eat", "bananas");
}
}
monkeys.getFood();
Note:
In general, fn.apply(null, args) is equivalent to fn(…args) with the parameter spread syntax, except args is expected to be an array-like object
1
2
3
4
5
const printItems = function(item1, item2, item3) {
console.log(item3);
};
printItems.apply(null, ["Foo", "Bar", "Baz"]);
The
bind()
function creates a new bound function. Calling the bound function generally results in the execution of the function it wraps, which is also called the target function. The bound function will store the parameters passed — which include the value of this and the first few arguments — as its internal state.
For example,
1
2
3
4
5
6
7
8
9
10
11
const alice = {
username: "Alice",
age: 35,
};
function sayHello(city, state) {
console.log(`Hello, ${this.username} from ${city}, ${state}!`);
}
const helloAlice = sayHello.bind(alice, 'Buffalo', 'New York');
helloAlice(); // console logs Hello, Alice from Buffalo, New York!
The call signature is same as that of call()
,
1
bind(thisArg[, arg1, arg2, /* …, */ argN])
That’s how we use the three utility functions. The post serves only as an introduction.
Feel free to explore more on the topic. Happy coding!