This is the second part of my three-parter on JavaScript function methods. Last time I talked about call()
. This time I’ll talk about apply()
.
Invoking Functions with apply()
apply()
, like call()
, is used to invoke a function. The difference is that call()
takes a list of arguments, while apply()
takes a single array (or array-like object) containing the arguments.
An example will clear things up. The following invokes sayThings()
3 different ways, with the same result each time.
function sayThings(something, somethingElse) {
console.log(something + ' and ' + somethingElse);
}
var thingsToSay = ['meow', 'woof'];
// logs "meow and woof" x 3
sayThings('meow', 'woof');
sayThings.call(this, 'meow', 'woof');
sayThings.apply(this, thingsToSay);
It may seem like a subtle difference, but being able to prepare arguments as an array can be very useful in certain situations.
Variable Number of Arguments
apply()
is super handy for functions that accept a variable number of arguments. Math.max()
is a great example.
var numbers = [8, 4, 9, 6, 1, 2];
var max = Math.max.apply(this, numbers);
console.log(max); // logs 9
Notice the line of code that invokes Math.max()
is not committed to any particular number of arguments. In this regard, apply()
grants us more flexibility, since it removes the constraint of needing to know how many arguments there will be.
Passing Arguments Along
apply()
makes it convenient to chain functions that accept the same set of arguments. No need to list out all the arguments for each subsequent function call. Since arguments
is an array-like object, we can just use apply()
to pass it along wholesale.
function doStuff(a, b, c) {
// do stuff with arguments...
// pass along
doMoreStuff.apply(this, arguments);
}
function doMoreStuff(a, b, c) {
// do more stuff with arguments...
// just to show they all made it here
console.log(a, b, c);
}
doStuff('carrot', 'star', 'spatula'); // logs "carrot" "star" "spatula"
This Again
You probably noticed that every example has passed this
in as the first argument to apply()
. Changing this argument will change the scope in which the function is invoked (which can be very useful). This might sound familiar — call()
does the exact same thing. Rather than copy/paste everything here, I’ll just refer you to my previous article.
Bonus Tip
It’s possible to invoke a function with the “wrong” number of arguments. This is true whether invoking a function directly or via a function method like call()
or apply()
. Nothing bad will happen. Unspecified arguments are left as undefined
(it’s common to write functions that expect this for optional arguments). Excess arguments are ignored.
function logThreeThings(a, b, c) {
console.log(a, b, c)
}
// 2 out of 3 arguments provided
logThreeThings('grass', 'bucket'); // logs "grass" "bucket" undefined
// 4 out of 3 arguments provided
logThreeThings('grass', 'bucket', 'hat', 'pickle'); // logs "grass" "bucket" "hat"
No matter how many arguments are expected, the arguments
local variable will always contain all provided arguments.
function insertPotato(a) {
console.log(arguments);
}
// extra argument provided
insertPotato('potato', 'bonus potato'); // logs ["potato", "bonus potato"]
Intermission
To review, apply()
gives you all the same power of call()
, with the added twist of letting you specify arguments as an array, which can make your life a lot easier in certain scenarios.
That’s it for apply()
. Next time I’ll talk about a slightly different animal: bind()
.