Function.prototype.apply()
Calls a function with a given this value and arguments taken from an array or array-like.
apply(thisArg)
apply(thisArg, argsArray)- Added in JavaScript ECMAScript 3 (1999)
Parameters
| Parameter | Type | Description |
|---|---|---|
$thisArg | any | The 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. |
$argsArrayoptional | Array | ArrayLike | null | undefined | An 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
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.
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.
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