Skip to main content

Flattening a nested array

Flattening an array means turning a nested structure into a single flat list of values. Modern JavaScript has the flat() method for exactly this, and it takes a depth argument; the other approaches (recursion, flatMap(), toString()) still have their niches.

Theory

TL;DR

  • arr.flat() unwraps one level of nesting.
  • arr.flat(2) unwraps two levels, arr.flat(Infinity) unwraps everything.
  • None of these approaches mutates the source array; they all return a new one.
  • Before ES2019 people wrote a recursive flatten on top of reduce() plus Array.isArray().
  • flatMap() is map() plus one level of flattening in a single pass.
  • toString().split(',') only works for numbers and strings, and it returns strings.

Quick example

Take this array:

javascript
const arr = [1, [2, 3], [4, [5, 6]]];

We want [1, 2, 3, 4, 5, 6]:

javascript
console.log(arr.flat(Infinity)); // [1, 2, 3, 4, 5, 6]

flat() and the flattening depth

The simplest way is flat() (ES2019 and later):

javascript
const flattened = arr.flat(); console.log(flattened); // [1, 2, 3, 4, [5, 6]]

By default flat() unwraps only one level of nesting. The depth is set by the argument:

javascript
const deeplyFlattened = arr.flat(2); console.log(deeplyFlattened); // [1, 2, 3, 4, 5, 6]
  • flat(1) is one level,
  • flat(2) is two levels,
  • flat(Infinity) is full flattening, whatever the depth.

An example with deep nesting:

javascript
const nested = [1, [2, [3, [4]]]]; console.log(nested.flat(Infinity)); // [1, 2, 3, 4]

This is the handiest and most modern way to flatten an array. As a bonus, flat() also drops the holes of a sparse array: [1, , 3].flat() gives [1, 3].

Recursion, the way it was done before flat()

javascript
function flatten(arr) { return arr.reduce( (acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val), [] ); } console.log(flatten([1, [2, [3, 4]], 5])); // [1, 2, 3, 4, 5]
  • check every element: if it is an array, call flatten recursively;
  • if it is not, push the value into the result.

This version is still useful when you need custom logic, for example skipping null or flattening only certain branches.

toString() for numbers and strings

javascript
[1, [2, [3, 4]]].toString().split(','); // ["1", "2", "3", "4"]

This works only when the array holds no objects and no null, because everything is converted to strings. Numbers come back as strings too, so it is more of a trick than a real approach.

flatMap() for transforming while flattening

javascript
const arr = [1, 2, [3, 4]]; const result = arr.flatMap(x => (Array.isArray(x) ? x : [x])); console.log(result); // [1, 2, 3, 4]

flatMap() transforms elements and flattens one level at the same time, so it saves a pass compared with map().flat().

Comparing the options

WayWorks withDepthMutatesModern
arr.flat()array1 by defaultNoYes, ES2019 and later
arr.flat(Infinity)multi-dimensionalall levelsNoYes
RecursionarrayanyNoYes, universal
flatMap()array1 levelNoYes
toString().split()numbers, stringsall levelsNoLimited

Bottom line: to flatten an array,

javascript
const flat = arr.flat(Infinity);

is short, safe and clear.

Common mistakes

  • Expecting flat() to unwrap everything. With no argument it removes exactly one level; deep structures need flat(Infinity).
  • Assuming flat() mutates the array. It returns a new array, so the result has to be assigned: arr = arr.flat().
  • Running toString().split(',') on objects. Objects turn into [object Object], while null and undefined become empty strings.
  • Losing types after split(). Numbers come back as strings, so an extra .map(Number) is required.
  • Recursion without a type check as the base case. Without Array.isArray(val) a string would also go into the recursion, since it is iterable.
  • Using flatMap() for deep flattening. It removes only one level, so [[1, [2]]] stays nested in the result.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.