Flatten a Nested Array
Flattening a nested array is a one-line job most of the time, but pre-built `Array#flat` is shallow by default and the depth parameter has surprises. This snippet starts with the modern built-in, adds a recursive deep-flatten that works in any environment, and ends with the iterative stack version that avoids stack-overflow on pathological inputs. Three flavours, one mental model.
410 views
4
const nested = [1, [2, [3, [4]]]];
console.log(nested.flat()); // [1, 2, [3, [4]]]
console.log(nested.flat(2)); // [1, 2, 3, [4]]
console.log(nested.flat(Infinity)); // [1, 2, 3, 4]Array.prototype.flat(depth) ships in every modern runtime (Node 11+, every evergreen browser). The default depth is 1, which is the most common gotcha. Pass Infinity for an unbounded deep flatten when you do not know how deep the nesting goes. Note that flat also drops sparse holes (skipping empty slots), which is usually the right behaviour for data pipelines but can surprise you if you rely on positional indexes.
function flattenDeep(array) {
const result = [];
for (const item of array) {
if (Array.isArray(item)) {
result.push(...flattenDeep(item));
} else {
result.push(item);
}
}
return result;
}
console.log(flattenDeep([1, [2, [3, [4, [5]]]]]));
// [1, 2, 3, 4, 5]When you cannot rely on Array#flat (very old runtimes, or a polyfill-free environment) the recursive version is the textbook implementation. It walks every item, recurses on arrays, and pushes leaves onto the result. The classic mistake is result.concat(...) inside the loop, which allocates a fresh array each iteration and drags time complexity toward O(n^2); using result.push(...flattenDeep(item)) keeps it linear. Recursion also makes this trivial to extend to non-array iterables (just check Symbol.iterator).
function flattenIterative(array) {
const stack = [...array];
const result = [];
while (stack.length > 0) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next);
} else {
result.push(next);
}
}
return result.reverse();
}
console.log(flattenIterative([1, [2, [3, [4]]]]));
// [1, 2, 3, 4]Recursion blows the call stack on degenerate inputs like [[[[[[1]]]]]] nested thousands of layers deep, which can happen when ingesting JSON from untrusted sources. Switching to an explicit stack moves the work onto the heap so the only practical limit is memory. Because pop reverses traversal order, the result is built backwards and we reverse() once at the end (still O(n)). Reach for this version when you flatten user-supplied data, or any input you cannot control the depth of.
