Function.prototype.apply()

Calls a function with a given this value and arguments taken from an array or array-like.

Signature
apply(thisArg)
apply(thisArg, argsArray)
  • Added in JavaScript ECMAScript 3 (1999)

Parameters

ParameterTypeDescription
$thisArganyThe value of this provided for the call. If the function is not in strict mode, null and undefined are replaced with the global object, and primitive values are converted to objects.
$argsArrayoptionalArray | ArrayLike | null | undefinedAn array-like object specifying the arguments with which the function should be called, or null or undefined if no arguments should be provided.

Return value

anyThe result of calling the function with the specified this value and arguments.

Errors

Throws a TypeError if the value it is called on is not callable or if argsArray is neither array-like nor nullish, and can throw a RangeError when argsArray exceeds the engine's argument-count limit.

Changelog

  • PHP ECMAScript 5 (2009)argsArray may be any array-like object; ES3 required a real array. Strict-mode functions also stopped substituting globalThis for a nullish thisArg.
  • PHP ECMAScript 2015Spread syntax — fn(...args) and new Fn(...args) — covers most uses of apply() and works with constructors and any iterable, not just array-likes.

apply() invokes a function immediately with an explicit this and an argument list you hand over as a single array or array-like object. Everything else about it matches call().

When to reach for it

  • You have the arguments in a variable already and the target expects them positionally — Math.max.apply(null, scores).
  • Forwarding an unknown number of arguments through a wrapper, especially old arguments-based code.
  • Array-like receivers. Array.prototype.map.apply(arrayLike, [fn]) pushes both the receiver and the callback through in one step.

What trips people up

Spread syntax has largely replaced it. Math.max(...scores) is shorter, works on any iterable (not just array-likes), and works with new, which apply() cannot do. Reach for apply() when you genuinely need to set this and the arguments together and the source is an array-like without Symbol.iterator.

The other hazard is size. Both apply() and spread push every element onto the call stack as a real argument; engines cap this somewhere in the tens or hundreds of thousands and throw a RangeError past it. For large arrays use a reduce or a chunked loop instead of apply().

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Find the largest value in an existing array with Math.max
  • Append one array onto another in place via Array.prototype.push
  • Run an array method against an array-like object such as arguments
  • Forward a wrapper function's arguments unchanged to the function it wraps

Frequently asked questions

Should I use apply() or spread syntax?

Use spread (fn(...args)) unless you also need to set this, because spread is shorter, accepts any iterable, and works with new. Reach for apply() when you need both an explicit this value and a dynamic argument list, or when the source is an array-like with no Symbol.iterator.

Why does Math.max.apply(null, hugeArray) throw a RangeError?

Because apply() passes every element as a separate stack argument and engines limit how many arguments a call may have. For large arrays reduce instead: hugeArray.reduce((a, b) => Math.max(a, b), -Infinity).

What happens if I pass null as the second argument to apply()?

The function is called with no arguments at all, exactly as if you had passed an empty array. null and undefined are both accepted for argsArray; any other non-array-like value throws a TypeError.

More examples

Working with array-like objects

Any object with a length and integer-keyed properties works as either the receiver or the argsArray. The last call treats the arguments object as the receiver of join, producing "1+2+3" without converting it to an array first.

Example · javascript
const arrayLike = { length: 3, 0: "x", 1: "y", 2: "z" };

// Copy an array-like into a real array
console.log(Array.prototype.slice.apply(arrayLike));

// Set both the receiver and the callback in one call
console.log(Array.prototype.map.apply(arrayLike, [(s) => s.toUpperCase()]));

function collect() {
  return Array.prototype.join.apply(arguments, ["+"]);
}
console.log(collect(1, 2, 3));

Merging in place, and hitting the argument limit

push.apply mutates target rather than allocating a new array, which is why the pattern survived spread syntax. The second half shows the ceiling: 200,000 arguments is enough to raise a RangeError in most engines.

Example · javascript
const target = [1, 2];
Array.prototype.push.apply(target, [3, 4, 5]);
console.log(target);

const big = new Array(200000).fill(0);
try {
  Math.max.apply(null, big);
  console.log("200k args accepted by this engine");
} catch (e) {
  console.log("blew the argument limit:", e.constructor.name);
}

Discussion

  • Be the first to comment on this lesson.