JavaScript Array concat with Non-Array Arguments

In JavaScript, Array.prototype.concat() merges two or more arrays into a single new array, but it also accepts non-array values as arguments. While arrays are automatically unpacked (flattened by one level) into the result, non-array arguments—such as primitive values, plain objects, and standard array-like objects—are appended directly as individual elements. This guide explains how the concat method processes different non-array data types and how you can override this default behavior using Symbol.isConcatSpreadable.

Primitive Values

When you pass primitive values (such as numbers, strings, booleans, null, undefined, symbols, or BigInts) to concat(), JavaScript treats each primitive as an individual element and appends it to the newly created array.

const baseArray = [1, 2];

const result = baseArray.concat(3, 'hello', true, null, undefined);

console.log(result);
// Output: [1, 2, 3, 'hello', true, null, undefined]

Objects and Functions

Plain objects, functions, dates, regular expressions, and other reference types are not flattened. The reference to the object is simply added as a single element in the resulting array.

const baseArray = ['a', 'b'];
const userObject = { id: 1, name: 'Alice' };

const result = baseArray.concat(userObject);

console.log(result);
// Output: ['a', 'b', { id: 1, name: 'Alice' }]

Because reference types are copied by reference (shallow copy), mutating the original object after the concatenation will reflect in the new array.

Array-like Objects

By default, array-like objects (such as arguments, NodeList, or custom objects with numeric keys and a length property) are treated as plain objects rather than arrays. Consequently, concat() inserts the entire array-like object as one element instead of spreading its indexed values.

const baseArray = [1, 2];
const arrayLike = {
  0: 'a',
  1: 'b',
  length: 2
};

const result = baseArray.concat(arrayLike);

console.log(result);
// Output: [1, 2, { 0: 'a', 1: 'b', length: 2 }]

Controlling Behavior with Symbol.isConcatSpreadable

JavaScript uses the well-known symbol Symbol.isConcatSpreadable to determine whether an argument should be flattened by concat():

You can explicitly set [Symbol.isConcatSpreadable]: true on an array-like object to force concat() to flatten its indexed elements into the new array.

const baseArray = [1, 2];
const spreadableArrayLike = {
  [Symbol.isConcatSpreadable]: true,
  0: 'a',
  1: 'b',
  length: 2
};

const result = baseArray.concat(spreadableArrayLike);

console.log(result);
// Output: [1, 2, 'a', 'b']

Conversely, setting [Symbol.isConcatSpreadable]: false on an array causes concat() to treat that array as a single element without unpacking it.

Summary

Array.prototype.concat() distinguishes between values based on their spreadability:

  1. Primitives and standard objects are appended as single items.
  2. Array-like objects are not unpacked unless explicitly configured.
  3. Symbol.isConcatSpreadable controls whether any object or array is flattened during the concatenation process.