cf.completefrontend

Write the codeEasy

Write flatten(array, depth) to flatten nested arrays up to depth levels, without using flat.

Before you start

What's a hole in an array?

An array's length counts slots, and a slot can be empty: no element at all, not even undefined. That empty slot is called a hole, and an array with holes is called sparse. Reading a hole gives undefined, the value you get for any property that doesn't exist, so it looks like an element holding undefined. Object.keys, which lists the indexes an array really has, tells the two apart:

const withHole = [1, , 3]; // nothing between the commas
const withUndefined = [1, undefined, 3];
 
withHole.length;      // 3
withUndefined.length; // 3
withHole[1];          // undefined
withUndefined[1];     // undefined
Object.keys(withHole);      // ["0", "2"]: there's no element at index 1
Object.keys(withUndefined); // ["0", "1", "2"]: there is one, and its value is undefined

Holes appear in a few ways:

HowExampleResult
A gap in an array literal[1, , 3]A hole at index 1
new Array with one numbernew Array(3)Three holes, and length is 3
delete on an elementdelete arr[1]Index 1 becomes a hole, and length doesn't change
Writing past the endarr[5] = 6 on [1, 2, 3]Holes at indexes 3 and 4, and length is 6
Making length biggerarr.length = 5 on [1, 2, 3]Holes at indexes 3 and 4

Consoles mark holes so you can spot them: Chrome shows [1, , 3] as [1, empty, 3], and Node as [ 1, <1 empty item>, 3 ].

Built-in methods don't agree on what to do with a hole: some skip it, some keep it in their result, and some read it as undefined, or write null in JSON. That's why every task that rebuilds one of them says exactly what to do with holes. Here's [1, , 3] going through a few:

CallResultWhat happened to the hole
[1, , 3].filter(() => true)[1, 3]Skipped: the callback isn't called for it, and the result has no hole
[1, , 3].map((n) => n * 10)[10, , 30]Skipped, but kept: the result has a hole in the same place
[1, , 3].reduce((sum, n) => sum + n)4Skipped: 1 starts the total, and the callback runs once, to add 3
[1, , 3].flat()[1, 3]Dropped
Array.from([1, , 3])[1, undefined, 3]Read as undefined, which becomes a real element
JSON.stringify([1, , 3])"[1,null,3]"Written as null

depth defaults to 1, and Infinity flattens everything. Behave like Array.prototype.flat: skip holes, flatten only real arrays (not strings or array-likes), and don't mutate the input.

Write this
function flatten(array, depth = 1) {
  // your code
}
 
// flatten([1, [2, [3, [4]]]]);           // [1, 2, [3, [4]]]
// flatten([1, [2, [3, [4]]]], 2);        // [1, 2, 3, [4]]
// flatten([1, [2, [3, [4]]]], Infinity); // [1, 2, 3, 4]

Solve it in the editor, with tests

The answer

Write it yourself first. Then compare it with a reference solution and the checks it passes.

Checking your sign-in…