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().

JavaScript function methods: 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().