Flattening Arrays in JavaScript

Hero image for Flattening Arrays in JavaScript. Image by Chris Robert.
Hero image for 'Flattening Arrays in JavaScript.' Image by Chris Robert.

Working with nested arrays is common in JavaScript, especially when dealing with complex data structures in booking systems or ecommerce platforms. In simple terms, 'flattening' an array means taking values out of nested arrays and placing them into a new array in the same lefttoright order. Only arrays are opened up. Values that are not arrays are kept as they are.

In this article, I will cover different ways to flatten arrays in JavaScript, from the modern flat() method to recursive and stackbased approaches. I will also explain how depth affects the result, what happens to values that are not arrays, and when a custom helper may be more appropriate than the builtin method.


What Does It Mean to Flatten an Array?

Starting with the basics, flattening removes one or more levels of array nesting. It does not change the values themselves; it only changes where those values sit in the array structure. For example:

const nestedArray = [1, [2, 3], "four", [{ five: 5 }], null];const flattenedArray = nestedArray.flat();console.log(flattenedArray);[1, 2, 3, "four", { five: 5 }, null]

In this example, [2, 3] and [{ five: 5 }] are nested arrays, so their contents move into the new array. The string, object, and null value are not arrays, so they are copied into the result unchanged.

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

By default, flat() only removes one level of nesting. A deep flatten removes every nested array until no arrays remain inside the result.


Using Array.prototype.flat()

The simplest way to flatten arrays in modern JavaScript is with the .flat() method, introduced in ECMAScript 2019 (ES10).

Basic Usage

const nestedArray = [1, [2, 3], [4, 5]];const flatArray = nestedArray.flat();console.log(flatArray);  // Output: [1, 2, 3, 4, 5]

However, by default, .flat() only flattens the array one level deep.

Flattening Deeper Arrays

To flatten arrays with deeper nesting, you can specify the depth as an argument. For example:

const deepNestedArray = [1, [2, [3, [4, 5]]], 6];const fullyFlatArray = deepNestedArray.flat(3);console.log(fullyFlatArray);  // Output: [1, 2, 3, 4, 5, 6]

Or, if you want to flatten to an infinite depth, you can quite literally pass Infinity in:

const fullyFlattened = deepNestedArray.flat(Infinity);console.log(fullyFlattened);  // Output: [1, 2, 3, 4, 5, 6]

Empty Slots in Sparse Arrays

flat() also removes empty slots in sparse arrays at the levels it flattens:

const sparseArray = [1, , 3, [4, , 6]];console.log(sparseArray.flat());// [1, 3, 4, 6]

An empty slot is not the same thing as undefined. If an array contains undefined as an actual value, that value remains in the result.

When .flat() Might Not Be Available

The web moves fast, and 2019 wasn't all that long ago, so there's a chance that it may not be supported in your browser support matrix, especially if you're still targeting IE11. In those situations, alternative methods would be required.


Flattening Arrays Without .flat()

Using Recursion

As you might have already guessed, a classic approach to flattening arrays would be to use recursion like this:

const flattenArray = (array: unknown[]): unknown[] =>  array.reduce<unknown[]>(    (result, value) =>      Array.isArray(value)        ? result.concat(flattenArray(value))        : result.concat(value),    []  );const nestedArray = [1, [2, [3, [4, 5]]], 6];console.log(flattenArray(nestedArray));   // Output: [1, 2, 3, 4, 5, 6]

The method in this example checks if each element is an array. If so, it recursively flattens it; otherwise, it adds the element to the accumulator.

Using a Stack

A stackbased version avoids recursive calls by processing the values iteratively:

const flattenUsingStack = (arr: any[]): any[] => {  const stack = [...arr];  const result: any[] = [];  while (stack.length) {    const next = stack.pop();    if (Array.isArray(next)) {      stack.push(...next);    } else {      result.push(next);    }  }  return result.reverse();};const nestedArray = [1, [2, [3, [4, 5]]], 6];console.log(flattenUsingStack(nestedArray));  // Output: [1, 2, 3, 4, 5, 6]

With this approach, we can avoid recursion, which can be beneficial for very large arrays that might otherwise cause stack overflow errors with recursive solutions.


Performance Considerations

  • .flat() is usually the clearest option in modern JavaScript and should be the default choice when browser support allows it.
  • Recursive functions are concise and useful for explaining the underlying logic, but very deeply nested arrays can risk call stack errors.
  • Stackbased approaches avoid recursive calls, which can make them safer for unusually deep nesting.

When performance matters, I would recommend benchmarking with realistic data. Array size, nesting depth, JavaScript engine, and allocation patterns can all affect the final result.


Wrapping Up

Flattening arrays in JavaScript can be straightforward with modern methods like .flat(), but older techniques such as recursion and stackbased approaches are invaluable for compatibility and understanding the underlying principles.

Key Takeaways

  • The .flat() method (introduced in ES10) is the simplest way to flatten arrays.
  • Use .flat(Infinity) to flatten arrays with arbitrary nesting levels.
  • Recursive and stackbased methods provide compatibility for environments where .flat() isn't supported.
  • Choose the right method based on browser support requirements and data complexity.

Understanding these techniques will help you choose the right approach for array flattening, no matter the JavaScript environment you're working with.


Untangling a delivery problem?

Send the symptoms, constraints, and affected routes. I'll help identify whether the issue sits in the application, platform, content model, deployment path, or search surface.