A few days ago I was asked if I could tell the difference between apply
, call
and bind
.
Both apply
and call
used to call functions and there are dozens of posts explaining how they do that.
They're expecting this
as their first argument, and if you ever read this clever comparison on Stack Overflow:
Think of a in apply for array of args and c in call for columns of args.
you'll hardly ever forget what's the only real difference.
apply
expects the arguments after this
in array-like form while call
expects them individually.
Because of No Autobinding in React
I used bind
regularly, but I still had no idea how it compared to apply
or call
, so here are my findings:
Similarities
- All three functions accept
this
as their first argument.bind
is morecall
-like meaning that it expects the arguments to be passed individually.
Differences
apply
andcall
used to invoke functions,bind
creates a new function. When you invoke this function it will has itsthis
keyword set to the value you provided as first argument.
var cat = {
name: 'Milu',
greet: function (greeting) {
return greeting + ', ' + this.name;
}
};
cat.greet.apply(cat, ['Hi']); // returns Hi, Milu
cat.greet.call(cat, 'Hello'); // returns Hello, Milu
var greetBound = cat.greet.bind(cat, 'Hey'); // returns a function
greetBound() // returns Hey, Milu
These things can be found in the documentation so let's do something what isn't there.
Invocation with Function objects
Below is a function purr
, which in fact is a Function
object. Every Function
object has a
name
property so the following call will result in:
function purr() {
return 'purrs at a frequency of 20 to 30 vibrations per second';
}
var greetBound = cat.greet.bind(purr, ['Hey']);
greetBound(); // returns Hey, purr
The same thing will happen when you call apply
or call
while providing purr
as first argument.
Invocation with an array of arguments
Passing an array of arguments to bind
then calling the bound function will have the same effect like
passing it to call
:
var cat = {
name: 'Milu',
greet: function (greeting) {
return greeting + ', ' + this.name;
}
};
cat.greet.call(cat, ['Hi', 'Hello']); // returns Hi,Hello, Milu
var greetBound = cat.greet.bind(cat, ['Hi', 'Hello']);
greetBound(); // returns Hi,Hello, Milu
bind
converts its second argument to string before passing it to the bound function.
When to use bind
Bind is really just a call
except that the invocation of the bound function can be delayed.
This reminds us to callbacks functions. Sadly, most of the examples I encountered did use bind
with callback functions but they didn't had the most thoughtful design,
which justified the usage of bind
:
var Widget = function () {
this.counter = 0;
$('button').on('click', function () {
this.counter += 1;
$('span').text(this.counter);
}.bind(this));
};
A simpler widget:
var Widget = function () {
var counter = 0;
$('button').on('click', function () {
counter += 1;
$('span').text(counter);
});
};
Browsing through dozens of examples I saw that bind
is more extensively used where the code
has conventional object-oriented design - which I've been avoiding altogether when it comes to JavaScript, and it pretty
much explains why I had no idea how it compares to call
and apply
.
Do you have a specific scenario where bind
is inevitable, or more appropriate? Let me know in the comments!