Array.prototype.concat()
Merges arrays and values into a new array without modifying any of the inputs.
concat()
concat(value1)
concat(value1, value2)
concat(value1, value2, /* …, */ valueN)- Added in JavaScript ES3
Parameters
| Parameter | Type | Description |
|---|---|---|
$value1, …, valueNoptional | Array | any | Arrays and/or values to concatenate into a new array. If all valueN parameters are omitted, concat returns a shallow copy of the existing array on which it is called. |
Return value
ArrayA new Array instance containing the elements of the original array followed by each argument's contents.
Errors
Throws a TypeError if the resulting array would exceed the maximum length of 2^53 - 1.
Changelog
- PHP ES3Introduced on Array.prototype.
- PHP ES2015Spreading behaviour became configurable through Symbol.isConcatSpreadable, and species constructors control the type of the returned array.
concat() builds a new array from the receiver plus every argument, leaving all inputs untouched. Array arguments are spread one level: their elements are copied in individually. Non-array arguments are appended as single elements.
When to reach for it
Use it in code that must not mutate its inputs — reducers, state updates, pure helper functions — where push() would be a bug. It also handles very large arrays better than spread syntax: a.push(...b) passes every element of b as a separate function argument and blows the argument limit somewhere around a hundred thousand elements, while a.concat(b) has no such ceiling.
What trips people up
The spreading is exactly one level deep. [1].concat([[2]]) yields [1, [2]], not [1, 2]. If you need full flattening, use a flatten operation instead.
The copy is shallow, so nested objects are shared between input and output. And because the receiver is spread while a bare value is not, [].concat(maybeArray) is a compact idiom for "normalise this into an array" — it wraps a scalar and passes an array through unchanged.
Example
When to use it
- Build an updated list in a reducer without mutating the previous state
- Merge several arrays of results into one before rendering
- Normalise a value that may be either a single item or an array
- Append a very large array where push with spread would exceed the argument limit
Frequently asked questions
Does concat() change the original array?
No, concat() is a copying method: it returns a new array and leaves both the receiver and every argument array unmodified.
Should I use concat() or the spread operator to merge arrays?
Spread reads better for a few small arrays, but concat() is safer for very large ones because spreading into a function call can exceed the engine's maximum argument count.
Why is my nested array still nested after concat()?
concat() spreads only one level of array arguments, so an array inside an argument array is copied as a single element; use a flatten operation for deeper structures.
More examples
Immutable state updates
The original array keeps its single item, so a previous snapshot of state stays valid. The last line shows the copy is shallow: unchanged items are the same object references, which is exactly what identity-based change detection wants.
const todos = [{ id: 1, text: "write" }];
function addTodo(list, todo) {
return list.concat(todo); // never mutates list
}
const next = addTodo(todos, { id: 2, text: "review" });
console.log(todos.length); // 1 — previous state intact
console.log(next.length); // 2
console.log(next[0] === todos[0]); // true — shallow, items sharedConcat versus push with spread
concat() handles a 200,000-element merge in one call. Spreading the same array into push() passes each element as a separate argument and can exceed the engine's call limit, so a loop or concat is the safe form.
const base = [0];
const big = new Array(200000).fill(1);
const merged = base.concat(big);
console.log(merged.length); // 200001 — no argument limit
// push(...big) can throw "too many arguments" at this size.
for (const v of big) base.push(v);
console.log(base.length); // 200001Controlling spreading with Symbol.isConcatSpreadable
Setting Symbol.isConcatSpreadable to false makes concat treat a real array as a single element. Setting it to true on a plain array-like object makes concat spread it, which is otherwise not done for non-arrays.
const nested = [1, 2];
console.log([0].concat(nested)); // [0,1,2] — spread by default
nested[Symbol.isConcatSpreadable] = false;
console.log([0].concat(nested)); // [0,[1,2]] — kept whole
const arrayLike = { length: 2, 0: "x", 1: "y", [Symbol.isConcatSpreadable]: true };
console.log([].concat(arrayLike)); // ['x','y']
Discussion