Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

JavaScript (ES2026)  Module 6 – Arrays and array methods

flat, flatMap, Array.from and array-likes

Flatten nested arrays with flat() and flatMap(), build arrays from strings, Sets and array-likes with Array.from(), and generate ranges without holes.

  • Beginner
  • 15 minutes
  • Examples run with Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Remove levels of nesting from an array with flat() and a chosen depth
  • Map and flatten in one step with flatMap(), dropping items by returning []
  • Create arrays from iterables and array-likes with Array.from()
  • Generate ranges and sequences with Array.from() and a length
  • Explain the difference between Array(n), Array.of(n) and an array of n undefined values

Before you start

What you’ll learn · Before you start

What you will learn

  • Remove levels of nesting from an array with flat() and a chosen depth
  • Map and flatten in one step with flatMap(), dropping items by returning []
  • Create arrays from iterables and array-likes with Array.from()
  • Generate ranges and sequences with Array.from() and a length
  • Explain the difference between Array(n), Array.of(n) and an array of n undefined values

Before you start

On this page

flat() returns a new array in which nested arrays are replaced by their items, one level deep by default: [1, [2, [3]]].flat() gives [1, 2, [3]], flat(2) goes two levels and flat(Infinity) every level. flatMap(fn) maps each item and flattens the results one level, so a callback that returns [] drops an item and one that returns [a, b] adds two. Array.from(source, mapper) builds a real array from anything iterable, such as a string, a Set, a Map or a generator, or array-like, an object with a length and numbered keys such as arguments or a page’s NodeList, and can map each item as it copies. Array.from({ length: n }, (_, i) => …) is the usual way to generate ranges and sequences. And Array(3) makes three empty slots, while Array.of(3) makes [3]. This lesson runs each one, including the depth at which flat(Infinity) gives up.

flat(): flatten to a depth

flat() with depths 1, 2 and Infinity JavaScript · flat-depth.mjs
const nested = [1, [2, [3, [4]]]];

console.log(JSON.stringify(nested.flat())); // depth 1, the default
console.log(JSON.stringify(nested.flat(2)));
console.log(JSON.stringify(nested.flat(Infinity))); // every level
console.log(JSON.stringify(nested)); // flat() returns a new array

// Holes are dropped, at every level that is flattened.
console.log([1, , 3, [4, , 6]].flat());

// Only real arrays are flattened: strings, Sets and array-likes stay as they are.
console.log([['a'], 'bc', new Set([1]), { length: 1, 0: 'x' }].flat());

Output

[1,2,[3,[4]]]
[1,2,3,[4]]
[1,2,3,4]
[1,[2,[3,[4]]]]
[ 1, 3, 4, 6 ]
[ 'a', 'bc', Set(1) { 1 }, { '0': 'x', length: 1 } ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node flat-depth.mjs

The depth says how many levels of brackets to take away, and each call returns a new array:

flat() removes one level of nesting from [1, [2, [3, [4]]]], flat(2) two levels, and flat(Infinity) every level.nested[1, [2, [3, [4]]]]nested.flat() or flat(1)[1, 2, [3, [4]]]nested.flat(2)[1, 2, 3, [4]]nested.flat(Infinity)[1, 2, 3, 4]one levelone more levelevery level left

What each depth of flat() removes

Text description of the diagram

Four boxes, one above the other, each showing the result of flat with a larger depth on the same array.

  1. The array nested is [1, [2, [3, [4]]]]: the number 4 sits four levels deep.
  2. nested.flat(), the same as flat(1), takes away one level of brackets: [1, 2, [3, [4]]].
  3. nested.flat(2) takes away two levels: [1, 2, 3, [4]].
  4. nested.flat(Infinity) takes away every level: [1, 2, 3, 4].

Each call returns a new array; nested itself never changes.

Two details of the output are easy to miss. flat() drops holes at every level it flattens, so [1, , 3, [4, , 6]].flat() has four items. And it flattens only real arrays: the string 'bc', the Set and the array-like object stayed as single items, because the standard checks each item with Array.isArray. Use flat() when data arrives as arrays of arrays, such as rows of a grid or pages of results, and you want one list.

flatMap(): map, then flatten one level

flatMap(fn) gives the same result as map(fn).flat(), in one pass and without the array in between:

Collecting the tags of every article JavaScript · tags.mjs
const articles = [
  { title: 'Monsoon trekking near Pune', tags: ['travel', 'monsoon'] },
  { title: 'Budget for a first job', tags: ['money'] },
  { title: 'Draft: packing list', tags: [], draft: true },
  { title: 'Monsoon recipes', tags: ['food', 'monsoon'] },
];

// map() gives one array of tags per article: an array of arrays.
console.log(articles.map((a) => a.tags));

// flatMap() maps and then flattens one level: one list of every tag.
const allTags = articles.flatMap((a) => a.tags);
console.log(allTags, [...new Set(allTags)]);

// Returning [] drops an item, so flatMap() can filter and map in one pass.
console.log(articles.flatMap((a) => (a.draft ? [] : [a.title.toUpperCase()])));

// Only one level is flattened: an array returned inside an array stays an array.
console.log([1, 2].flatMap((n) => [[n, n * 10]]));

Output

[ [ 'travel', 'monsoon' ], [ 'money' ], [], [ 'food', 'monsoon' ] ]
[ 'travel', 'monsoon', 'money', 'food', 'monsoon' ] [ 'travel', 'monsoon', 'money', 'food' ]
[
  'MONSOON TREKKING NEAR PUNE',
  'BUDGET FOR A FIRST JOB',
  'MONSOON RECIPES'
]
[ [ 1, 10 ], [ 2, 20 ] ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node tags.mjs

map() returned one array of tags per article. flatMap() returned one list of every tag, ready for a Set to drop the repeats. The third call shows its other use: the callback returns [] for drafts and a one-item array for everything else, so flatMap() filters and maps in a single pass. Only one level is flattened, whatever the callback returns: an array inside the returned array stays an array, as the last line shows. Like map(), the callback receives the item, its index and the whole array.

Deep nesting: where flat(Infinity) gives up

flat(Infinity) works through the levels by going one level deeper for each one, and each level uses a little of the engine’s call stack. Data nested thousands of levels deep, such as a thread of replies stored as arrays inside arrays, runs out of stack:

1,000 levels, 10,000 levels and a loop with its own stack JavaScript · deep-flatten.mjs
// Nested replies, one inside the other, `depth` levels deep.
function nest(depth) {
  let thread = ['reply'];
  for (let i = 0; i < depth; i++) thread = [thread];
  return thread;
}

// flat(Infinity) goes one level deeper for each level of nesting, and the engine runs out of stack.
for (const depth of [1000, 10000]) {
  try {
    console.log(`flat(Infinity), ${depth} levels:`, nest(depth).flat(Infinity));
  } catch (error) {
    console.log(`flat(Infinity), ${depth} levels:`, error.name);
  }
}

// A loop with its own stack of [array, next index] pairs handles any depth, in order.
function flattenAll(input) {
  const out = [];
  const stack = [[input, 0]];
  while (stack.length > 0) {
    const top = stack[stack.length - 1];
    const [array, index] = top;
    if (index === array.length) {
      stack.pop();
      continue;
    }
    top[1] = index + 1;
    if (!(index in array)) continue; // skip holes, as flat() does
    const item = array[index];
    if (Array.isArray(item)) stack.push([item, 0]);
    else out.push(item);
  }
  return out;
}
console.log('flattenAll, 100,000 levels:', flattenAll(nest(100000)));
console.log('flattenAll keeps the order:', flattenAll([1, [2, [3, , [4]], 5], [[6]]]));

Output

flat(Infinity), 1000 levels: [ 'reply' ]
flat(Infinity), 10000 levels: RangeError
flattenAll, 100,000 levels: [ 'reply' ]
flattenAll keeps the order: [ 1, 2, 3, 4, 5, 6 ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node deep-flatten.mjs

On Node.js 24.21.0, 1,000 levels flattened and 10,000 threw a RangeError (“Maximum call stack size exceeded”); the exact limit lies between the two and depends on the engine and its stack size. flattenAll avoids the call stack: it keeps its own list of the arrays it is inside, with the next index to read in each, so it flattens 100,000 levels, keeps the items in order and skips holes as flat() does. Most data is nowhere near that deep, but input you do not control can be, so code that flattens such input needs a loop like this, or a limit on the depth.

Array.from(): an array from anything iterable

Arrays from a string, a Set, a Map and an array-like JavaScript · from-sources.mjs
// A string: one item per code point. An emoji and its skin-tone modifier are two code points, each kept whole.
const reaction = '👍🏽';
console.log(reaction.length, Array.from(reaction).length);
console.log(Array.from('नमस्ते'));

// A Set and a Map: their items, in insertion order.
console.log(Array.from(new Set(['tea', 'coffee', 'tea'])));
const stock = new Map([['tea', 40], ['coffee', 12]]);
console.log(Array.from(stock), Array.from(stock.values()));

// A second argument maps each item as it is copied: it receives the item and its index.
console.log(Array.from(new Set([3, 4]), (n, i) => `${i}: ${n * n}`));

// An object with a length and numbered keys (an array-like).
console.log(Array.from({ length: 2, 0: 'first', 1: 'second' }));

Output

4 2
[ 'न', 'म', 'स', '्', 'त', 'े' ]
[ 'tea', 'coffee' ]
[ [ 'tea', 40 ], [ 'coffee', 12 ] ] [ 40, 12 ]
[ '0: 9', '1: 16' ]
[ 'first', 'second' ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node from-sources.mjs

Array.from() first looks for the source’s iterator, the protocol that for…of and spread also use:

  • Strings give one item per code point, never half of one. The thumbs-up with a skin-tone modifier is 4 UTF-16 code units long and 2 code points, so it becomes two whole items: the thumb and the modifier. Devanagari text gives letters, signs and the virama as separate code points: नमस्ते becomes six items, while a reader sees three characters, न, म and स्ते.
  • A Set gives its values and a Map its [key, value] pairs, in the order they were added; Array.from(map.values()) takes the values alone.
  • The second argument maps each item as it is copied. Unlike the callback of map(), it receives only two arguments, the item and its index.

When the source has no iterator, Array.from() treats it as an array-like and reads length and the keys from 0 up, as with the last object. An iterator wins when there is one.

Ranges and sequences

JavaScript has no range() built in. Array.from() with a length and a mapper makes one in a line:

Numbers, hours, letters and steps JavaScript · range.mjs
// { length: n } has no items, so Array.from() fills every index with the mapper's result.
console.log(Array.from({ length: 5 }, (_, i) => i));
console.log(Array.from({ length: 5 }, (_, i) => (i + 1) * 10));

// The hours of a time picker, as two-digit strings.
console.log(Array.from({ length: 24 }, (_, h) => String(h).padStart(2, '0')).join(' '));

// Letters by code point: A to Z, and the first Devanagari vowel letters.
console.log(Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i)).join(''));
console.log(Array.from({ length: 11 }, (_, i) => String.fromCodePoint(0x0905 + i)).join(' '));

// A range with a step: compute each value from its index rather than adding the step again and again.
const step = 0.1;
console.log(Array.from({ length: 5 }, (_, i) => Math.round(i * step * 10) / 10));

Output

[ 0, 1, 2, 3, 4 ]
[ 10, 20, 30, 40, 50 ]
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
ABCDEFGHIJKLMNOPQRSTUVWXYZ
अ आ इ ई उ ऊ ऋ ऌ ऍ ऎ ए
[ 0, 0.1, 0.2, 0.3, 0.4 ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node range.mjs

{ length: 5 } is an array-like with no items, so Array.from() calls the mapper for each of the five indexes and keeps what it returns; the first argument is undefined, and the _ name says it is not used. Two cautions come with sequences:

  • Code points follow the Unicode chart, not an alphabet. A to Z are 26 codes in a row. The Devanagari chart orders the letters of every language written in the script together, so the eleven code points from अ also include ऌ (vocalic L), ऍ (candra E) and ऎ (short E, which the Unicode names list gives for Kashmiri and Bihari languages and for Dravidian sounds). When a list must hold exactly the letters of one alphabet, write them out in an array.
  • Fractional steps. Adding 0.1 over and over collects rounding errors, so compute each value from its index, as the last line does, and round when the values must look exact. The exercise below asks for a range() with a step.

Array(n), Array.of(n) and holes

Holes, real undefined values, and one shared row JavaScript · holes.mjs
// Three ways to make "three of something", and what is really inside.
console.log(Array(3), Array(3).length); // three holes
console.log(Array.of(3)); // one item: the number 3
console.log(Array.from({ length: 3 })); // three real undefined values

// map() skips holes, so mapping Array(3) gives three holes back.
console.log(Array(3).map((_, i) => i));
console.log(Array.from({ length: 3 }, (_, i) => i));

// fill() puts the same value in every slot: with an array, the same array.
const shared = Array(3).fill([]);
shared[0].push('A1');
console.log(shared);

// Array.from() calls the mapper once per index, so each row is a new array.
const rows = Array.from({ length: 3 }, () => []);
rows[0].push('A1');
console.log(rows);

Output

[ <3 empty items> ] 3
[ 3 ]
[ undefined, undefined, undefined ]
[ <3 empty items> ]
[ 0, 1, 2 ]
[ [ 'A1' ], [ 'A1' ], [ 'A1' ] ]
[ [ 'A1' ], [], [] ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node holes.mjs

Array(3) creates an array whose length is 3 and that has no items at all: three holes. map(), forEach() and filter() skip holes, which is why mapping Array(3) gave three holes back. Array.of(3) creates an array whose one item is 3: it never treats a number as a length. Array.from({ length: 3 }) creates three real undefined values, which every method visits.

Array(3), Array.of(3) and Array.from({ length: 3 }, f)
Criterion Array(3)Array.of(3)Array.from
Length 313
Items three holesthe number 3what f returns for 0, 1 and 2
Seen by map() noyesyes
When to choose RarelyA list of valuesRanges and grids

The last two runs show the bug that fill() causes in grids. fill([]) puts the same array in every slot, so a seat added to row 0 appears in every row. Array.from() with a mapper calls it once per index, so each row is a new array.

Array-likes

An array-like is any object with a length and items under the keys 0, 1, 2 and so on. Strings, arguments and the NodeList that document.querySelectorAll() returns are array-likes, and so is a plain object written that way:

Using an array-like with and without Array.from JavaScript · array-likes.mjs
// An array-like: a length and items at index keys, but none of the array methods.
const marks = { length: 3, 0: 72, 1: 85, 2: 64 };
console.log(typeof marks.map, Array.isArray(marks));

// Array.from() turns it into a real array.
console.log(Array.from(marks).map((m) => m + 5));

// Array methods are generic: borrowed with call(), they work on it directly.
console.log(Array.prototype.map.call(marks, (m) => m + 5));
console.log(Array.prototype.join.call('abc', '-'));

// Spread needs an iterable. A plain array-like is not one, so spread throws.
try {
  console.log([...marks]);
} catch (error) {
  console.log(error.name);
}

// arguments is an array-like that is also iterable, so both work.
function total() {
  return [Array.isArray(arguments), Array.from(arguments).length, [...arguments].reduce((a, b) => a + b, 0)];
}
console.log(total(10, 20, 30));

// The length is converted to a whole number: negative or missing means empty.
console.log(Array.from({ length: 2.7 }), Array.from({ length: -1 }), Array.from({}));

Output

undefined false
[ 77, 90, 69 ]
[ 77, 90, 69 ]
a-b-c
TypeError
[ false, 3, 60 ]
[ undefined, undefined ] [] []

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node array-likes.mjs

A plain array-like has none of the array methods, so marks.map is undefined. There are two ways to work with one:

  • Copy it with Array.from(), then use any method. This is the usual choice in browser code: a NodeList has forEach() but no map() or filter(), and MDN’s page on it names Array.from() as the way to make it a real array.
  • Borrow a method with call(). Array methods are written to work on any object with a length and numbered keys, so Array.prototype.map.call(marks, f) maps the array-like directly.

Spread is not a third way for every array-like: [...marks] throws a TypeError, because spread needs an iterator and a plain object has none. arguments has one, so both spread and Array.from() work on it. The last line shows how Array.from() reads the length: it rounds 2.7 down to 2, and a negative or missing length means an empty array.

Array.fromAsync() for asynchronous sources

ECMAScript 2026 adds Array.fromAsync(), which collects an async iterable, such as pages of results that arrive one at a time, into an array, and returns a promise of that array:

Collecting pages that arrive one at a time JavaScript · from-async.mjs
// Pages of results arriving one at a time, as from a paginated API (simulated here, no network).
async function* pages() {
  for (const page of [['Asha', 'Ravi'], ['Meena'], ['Kabir', 'Zoya']]) {
    await new Promise((resolve) => setTimeout(resolve, 5));
    yield page;
  }
}

// Array.fromAsync() waits for every item of an async iterable and returns a promise of the array.
const byPage = await Array.fromAsync(pages());
console.log(byPage, byPage.flat());

Output

[ [ 'Asha', 'Ravi' ], [ 'Meena' ], [ 'Kabir', 'Zoya' ] ] [ 'Asha', 'Ravi', 'Meena', 'Kabir', 'Zoya' ]

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node from-async.mjs

It is supported by Chrome 121, Firefox 115, Safari 16.4 and Node.js 22 and later. QuickJS, which runs the Run buttons of this track, does not have it yet, so this example shows what Node.js 24.21.0 printed and cannot be run on the page. Async iterators themselves come later in the track, with promises and async functions.

JSON Viewer & Tree Editor Paste nested JSON and expand it level by level to see how deep its arrays go before you choose a depth for flat(). JavaScript & TypeScript Online Compiler Try flat(), flatMap() and Array.from() on data of your own.

Exercise: range() and chunk()

Exercise · Medium · JavaScript

Write range() and chunk() with Array.from

Write two helpers that a seat-booking page needs:

  • range(start, end, step = 1) returns the numbers from start up to, but not including, end, step apart. A negative step counts down, and then the numbers stay above end. When step points away from end, the result is empty. A step of 0, or one that is not a finite number, throws a RangeError.
  • chunk(array, size) splits array into arrays of size items, in order; the last one may be shorter. It returns new arrays and leaves array unchanged. A size that is not a whole number of at least 1 throws a RangeError.
range(1, 6)          // [1, 2, 3, 4, 5]
range(10, 0, -3)     // [10, 7, 4, 1]
range(0, 5, -1)      // []
chunk(['A1', 'A2', 'A3', 'A4', 'A5'], 2)  // [['A1', 'A2'], ['A3', 'A4'], ['A5']]

The starter code returns placeholders: run the sample tests to see what each helper still has to do.

Starter code · sequences.mjs

/** The numbers from start up to, but not including, end, step apart (a negative step counts down). */
export function range(start, end, step = 1) {
  // Replace this line with your code.
  return [start];
}

/** array split into arrays of size items, in order; the last one may be shorter. */
export function chunk(array, size) {
  // Replace this line with your code.
  return [array];
}
The sample tests · sequences.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { range, chunk } from './sequences.mjs';

test('range counts up and stops before end', () => {
  assert.deepEqual(range(1, 6), [1, 2, 3, 4, 5]);
  assert.deepEqual(range(0, 10, 3), [0, 3, 6, 9]);
  assert.deepEqual(range(5, 5), []);
});

test('a negative step counts down and stays above end', () => {
  assert.deepEqual(range(10, 0, -3), [10, 7, 4, 1]);
  assert.deepEqual(range(3, -1, -1), [3, 2, 1, 0]);
});

test('a step that points away from end gives an empty array', () => {
  assert.deepEqual(range(0, 5, -1), []);
  assert.deepEqual(range(5, 0), []);
});

test('a step of 0 or a step that is not finite throws a RangeError', () => {
  assert.throws(() => range(0, 5, 0), RangeError);
  assert.throws(() => range(0, 5, NaN), RangeError);
  assert.throws(() => range(0, 5, Infinity), RangeError);
});

test('chunk splits in order and the last chunk may be shorter', () => {
  const seats = Object.freeze(['A1', 'A2', 'A3', 'A4', 'A5']);
  assert.deepEqual(chunk(seats, 2), [['A1', 'A2'], ['A3', 'A4'], ['A5']]);
  assert.deepEqual(chunk(seats, 5), [['A1', 'A2', 'A3', 'A4', 'A5']]);
  assert.deepEqual(chunk(seats, 9), [['A1', 'A2', 'A3', 'A4', 'A5']]);
  assert.deepEqual(chunk(seats, 1).length, 5);
  assert.deepEqual(chunk([], 3), []);
});

test('chunk returns new arrays', () => {
  const seats = ['A1', 'A2'];
  const [first] = chunk(seats, 2);
  assert.notEqual(first, seats);
  first.push('A3');
  assert.deepEqual(seats, ['A1', 'A2']);
});

test('chunk needs a whole size of at least 1', () => {
  assert.throws(() => chunk([1, 2, 3], 0), RangeError);
  assert.throws(() => chunk([1, 2, 3], -2), RangeError);
  assert.throws(() => chunk([1, 2, 3], 1.5), RangeError);
});
A hint

Both helpers are one Array.from({ length: n }, (_, i) => …) once you know n. For range, n is Math.ceil((end - start) / step), but never below 0, and the item at index i is start + i * step. For chunk, n is Math.ceil(array.length / size), and chunk i is array.slice(i * size, (i + 1) * size).

The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Self-check

Check yourself

6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 6 What does [[1, 2], [3, [4]]].flat() return?

    Choose one answer.

    Show the answer to question 1

    Answer: [1, 2, 3, [4]]

    With no argument the depth is 1, so one level of brackets goes: the items of [1, 2] and of [3, [4]] move up one level, and [4], which was two levels deep, is now one level deep. flat(2) or flat(Infinity) would give [1, 2, 3, 4].

  2. Question 2 of 6 What does this code print?

    Read the code, then choose one answer.

    const lines = ['tea sugar', 'milk'];
    console.log(lines.flatMap((line) => line.split(' ')));
    Show the answer to question 2

    Answer: [ 'tea', 'sugar', 'milk' ]

    split(' ') returns an array of words for each line, and flatMap flattens those arrays one level into a single list. map with the same callback would give the array of arrays in the second choice.

  3. Question 3 of 6 Which of these expressions give [0, 1, 2]? Choose every one.

    Choose every answer that is right.

    Show the answer to question 3

    Answer:

    • Array.from({ length: 3 }, (_, i) => i)
    • [...Array(3).keys()]
    • Array.from(Array(3), (_, i) => i)

    Array.from calls its mapper for every index, holes included, and keys() lists every index of an array of length 3. map skips holes, so on Array(3) it returns three holes, and Array.of(3) is the one-item array [3].

  4. Question 4 of 6 What does flat-depth.mjs print?

    What does this program print? Choose one answer.

    const nested = [1, [2, [3, [4]]]];
    
    console.log(JSON.stringify(nested.flat())); // depth 1, the default
    console.log(JSON.stringify(nested.flat(2)));
    console.log(JSON.stringify(nested.flat(Infinity))); // every level
    console.log(JSON.stringify(nested)); // flat() returns a new array
    
    // Holes are dropped, at every level that is flattened.
    console.log([1, , 3, [4, , 6]].flat());
    
    // Only real arrays are flattened: strings, Sets and array-likes stay as they are.
    console.log([['a'], 'bc', new Set([1]), { length: 1, 0: 'x' }].flat());
    Show the answer to question 4

    Answer: it prints

    [1,2,[3,[4]]]
    [1,2,3,[4]]
    [1,2,3,4]
    [1,[2,[3,[4]]]]
    [ 1, 3, 4, 6 ]
    [ 'a', 'bc', Set(1) { 1 }, { '0': 'x', length: 1 } ]

    Each depth removes one more level, and flat returns a new array, so nested itself is unchanged on the fourth line. Holes are dropped at every level that is flattened, and only real arrays are flattened: the string, the Set and the array-like stay single items.

  5. Question 5 of 6 What happens with [...{ length: 2, 0: 'a', 1: 'b' }]?

    Choose one answer.

    Show the answer to question 5

    Answer: It throws a TypeError, because the object is not iterable

    Spread needs an iterator, and a plain object has none, even when it looks like an array. Array.from() reads its length and numbered keys instead, and gives ['a', 'b'].

  6. Question 6 of 6 const grid = Array(3).fill([]); grid[0].push('A1'); What is in grid now?

    Choose one answer.

    Show the answer to question 6

    Answer: [['A1'], ['A1'], ['A1']], because every slot holds the same array

    fill([]) evaluates [] once and puts that one array in all three slots, so a change through any slot shows in all of them. Array.from({ length: 3 }, () => []) calls the arrow once per slot and makes three arrays.

Interview questions

What is the difference between Array(3), Array.of(3) and Array.from({ length: 3 })? Array(3) treats a single number as a length: it creates an array of length 3 with no items, three holes, which map(), forEach() and filter() skip. With any other single argument, or with several, Array() puts the arguments in the array, which makes it easy to misread. Array.of(3) always puts its arguments in the array, so it gives [3], one item. Array.from({ length: 3 }) reads an array-like of length 3 and creates three real undefined values, and with a mapper, as in Array.from({ length: 3 }, (_, i) => i), it fills them in one step, giving [0, 1, 2]. Use Array.of() for a list of values and Array.from() with a length for ranges and grids.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    Write flatten(array, depth = 1) without using flat(), with the same results: holes skipped and only real arrays flattened. Then make it work for input nested 100,000 levels deep, where flat(Infinity) itself throws a RangeError in Node.js, and give the complexity of your version.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A page removes expired banners with const list = document.getElementsByClassName('expired'); for (let i = 0; i < list.length; i++) list[i].remove(); but half of the banners stay on the page. Explain exactly which ones stay and why, and give two correct ways to remove them all.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • flat(depth) returns a new array with depth levels of nesting removed, 1 by default; it drops holes and flattens only real arrays.
  • flatMap(fn) is map(fn).flat() in one pass; return [] to drop an item and an array of two to add two.
  • flat(Infinity) uses the call stack: in Node.js 24.21.0, 1,000 levels worked and 10,000 threw a RangeError. A loop with its own stack handles any depth.
  • Array.from(source, mapper) copies anything iterable, or else array-like; strings split by code point, and the mapper receives the item and its index.
  • Array.from({ length: n }, (_, i) => …) makes ranges and grids; compute fractional steps from the index.
  • Array(3) is three holes, Array.of(3) is [3], and fill([]) shares one array between every slot.
  • Array-likes need Array.from() or a borrowed method; spread works only when they are also iterable.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.