Both call
and apply
allow you to invoke a specific function and pass in a context, that will be this
within the function, as well as arguments. How you pass in the arguments for each method is different though and can certainly lead to frustration as you work to debug your code. Having spent some time debugging my own code due to this confusion, I figured it was worthwhile to write a blog post about it for reference, even if I'm the only one that refers to it in the future!
Call
As stated previously call
allows you to invoke a function, pass in your desired context as the first argument, as well as your input arguments. In the case of the call
method, you pass in the arguments individually and separated by commas.
One instance where it can be beneficial to use call
is when creating subclasses within JavaScript. Specifically if your subclass shares traits with your superclass, you can use call on the superclass to set the properties on the subclass. Here's a quick example.
var Business = function(name, location) {
this.name = name;
this.location = location;
};
var Restaurant = function(name, location, type) {
Business.call(this, name, location);
this.category = 'Restaurant';
this.type = type;
};
Restaurant.prototype = Object.create(Business.prototype);
Restaurant.prototype.constructor = Restaurant;
var SupplyStore = function(name, location, type) {
Business.call(this, name, location);
this.category = 'Supply Store'
this.type = type;
};
SupplyStore.prototype = Object.create(Business.prototype);
SupplyStore.prototype.constructor = SupplyStore;
var pizza = new Restaurant('House of Slices', 'Your Neighborhood', 'Pizza');
var officeSupplies = new SupplyStore('All Your Office Supply Needs', 'Next town over', 'Office Supply Store');
Another quick example of using call
is when you can use it to convert the arguments array of a function input from an array-like object to an array.
var addNumbers = function() {
var inputs = Array.prototype.slice.call(arguments, 0);
return inputs.reduce(function(previous, current) {
return previous + current;
}, 0);
};
var total = addNumbers(1, 2, 3, 4);
console.log(total); // 10
Apply
Now that I've discussed call
, you might wonder how apply
is any different, as they ostensibly do the same thing. apply
still takes a context as its first argument, but instead of taking individual arguments after that, apply
takes an array or array-like object instead.
In this somewhat contrived example, if you wanted to print out the character code for each letter in an array of unknown length, you could use apply
to invoke that function.
var testStringChars = 'hello there!'.split('');
var printCharacters = function() {
for (var i = 0; i < arguments.length; i++) {
console.log('character code for "' + arguments[i] + '" is ' + String.prototype.charCodeAt.call(arguments[i]));
}
};
printCharacters.apply(this, testStringChars);
Takeaway
The main takeaway here is that both call
and apply
both allow you to invoke functions and supply the context that it should be invoked with. The fundamental difference between the two is how the input arguments are passed in when invoked. call
takes its input arguments as individual inputs, while apply
takes an array or array-like object. If you have a good example for apply
please let me know!