Back to JavaScript
JavaScript
easy
mid

How would you implement a flatten array function in JavaScript?

Recursively flatten a nested array. Show the recursive reduce solution, an iterative stack version (no recursion-depth limit), and mention Array.prototype.flat(Infinity) as the built-in. Discuss the depth parameter.

4 min read·~12 min to think through

flatten is a classic recursion warm-up. Show you can do it three ways and know the tradeoffs.

1. Recursive with reduce (the expected answer)

js
function flatten(arr) {
  return arr.reduce(
    (acc, item) =>
      Array.isArray(item)
        ? acc.concat(flatten(item))   // recurse into nested arrays
        : acc.concat(item),
    []
  );
}
flatten([1, [2, [3, [4]], 5]]); // [1, 2, 3, 4, 5]

2. With a depth parameter (like the real flat())

js
function flatten(arr, depth = Infinity) {
  return depth < 1
    ? arr.slice()
    : arr.reduce(
        (acc, item) =>
          Array.isArray(item)
            ? acc.concat(flatten(item, depth - 1))
            : acc.concat(item),
        []
      );
}
flatten([1, [2, [3]]], 1); // [1, 2, [3]]

3. Iterative with a stack (no recursion-depth limit)

For very deeply nested arrays, recursion can blow the call stack. An explicit stack avoids that:

js
function flatten(arr) {
  const stack = [...arr];
  const result = [];
  while (stack.length) {
    const next = stack.pop();
    if (Array.isArray(next)) stack.push(...next); // push children back
    else result.push(next);
  }
  return result.reverse(); // pop reverses order, so reverse back
}

4. The built-in

js
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]

Array.prototype.flat(depth) exists — mention it, but interviewers want the manual implementation.

Talking points

  • concat vs pushconcat returns a new array (cleaner but allocates more); push(...item) mutates in place (faster).
  • Recursion depth — the recursive version is elegant but can stack-overflow on pathological input; the iterative stack version is bulletproof.
  • Array.isArray — the correct check, not typeof (arrays are objects).

The framing

"I'd start with the recursive reduce — it's the cleanest expression of the idea. Then I'd mention two things a senior cares about: a depth parameter to match the real flat(), and an iterative stack version that won't overflow on deeply nested input. flat(Infinity) is the built-in, but the point of the exercise is the recursion."

Follow-up questions

  • How would you handle extremely deep nesting that overflows the call stack?
  • What's the difference between concat and push(...) here?
  • How does Array.prototype.flat's depth parameter work?
  • Can you flatten while also removing duplicates?

Common mistakes

  • Using typeof instead of Array.isArray to detect nested arrays.
  • Mutating the input array instead of returning a new one.
  • Forgetting that the stack/pop version reverses order.
  • Not handling the depth parameter when asked.

Performance considerations

  • concat-based recursion allocates a new array at every level — O(n) extra allocations. A push-based or stack-based version is faster and more memory-friendly for large inputs.

Edge cases

  • Empty arrays and empty nested arrays.
  • Non-array values like null or objects — should pass through untouched.
  • Extremely deep nesting causing a RangeError in the recursive version.
  • Sparse arrays with holes.

Real-world examples

  • Flattening nested category trees or comment threads into a flat list for rendering.
  • Normalizing deeply nested API responses.

Senior engineer discussion

Seniors write the recursive version fast, then proactively raise stack-overflow risk and offer the iterative stack solution, add a depth parameter, and discuss concat-vs-push allocation cost. They also note flat() exists but the exercise is about demonstrating the algorithm.

Related questions