Array.prototype.concat()

Merges arrays and values into a new array without modifying any of the inputs.

Signature
concat()
concat(value1)
concat(value1, value2)
concat(value1, value2, /* …, */ valueN)
  • Added in JavaScript ES3

Parameters

ParameterTypeDescription
$value1, …, valueNoptionalArray | anyArrays 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

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

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.

Example · javascript
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 shared

Concat 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.

Example · javascript
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);   // 200001

Controlling 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.

Example · javascript
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

  • Be the first to comment on this lesson.