All topics
ES6+beginner

Array.from and Array-Like Objects

Converting iterables and array-like objects (things with a length and indices but no array methods) into real arrays, optionally with a mapping function.

Array.from converts anything iterable or array-like into a real array.

Array.from is like a customs officer who accepts either a passport (a genuine iterable) or, failing that, a numbered ticket stub with a stated headcount (an array-like's length and indices) — either way, everyone gets issued a real visitor badge (a genuine Array) with full building access afterward.

Key Concepts

1
    Array.from('hello');              // ['h','e','l','l','o']
    Array.from(new Set([1, 2]));      // [1, 2]
    Array.from(document.querySelectorAll('div'));
    Array.from(arguments);
2
Array-like means it has length and indices, and no array methods.
    const arrayLike = { 0: 'a', 1: 'b', length: 2 };
    Array.from(arrayLike);            // ['a', 'b']
    [...arrayLike];                   // TypeError -- not iterable
length
3
That is the difference from spread: Array.from handles both array-like and iterable; spread handles only iterable.
Array.from
4
Which is why Array.from(arguments) works and [...arguments] also works — arguments happens to be both — while a plain {0:..., length:...} object needs Array.from.
Array.from(arguments)[...arguments]arguments{0:..., length:...}Array.from
5
The second argument is a map function.
    Array.from({ length: 5 }, (_, i) => i);          // [0,1,2,3,4]
    Array.from({ length: 5 }, (_, i) => i * i);      // [0,1,4,9,16]
    Array.from(nodeList, el => el.textContent);
6
Array.from({ length: n }, fn) is the idiomatic way to build a range, and it is better than the alternatives:
Array.from({ length: n }, fn)
7
    new Array(5)                 // holes -- map and forEach SKIP them
    new Array(5).fill(0).map(...)  // works, two passes
    Array.from({length: 5}, ...)   // one pass, no holes
8
The first one is the trap: new Array(5).map((_, i) => i) returns five holes, because map does not visit empty slots.
new Array(5).map((_, i) => i)map
9
Where array-likes come from.
    arguments
    document.querySelectorAll  (a NodeList)
    getElementsByClassName      (an HTMLCollection -- and live)
    a regex match result
    strings, via index and length
10
Array.from copies, which is what you usually want with a live collection.
    const els = document.getElementsByClassName('x');   // live
    for (const el of Array.from(els)) el.remove();      // safe
Array.from
11
Iterating the live collection while removing skips elements, because the collection shrinks underneath the loop. Copying first avoids it.
12
Array.of is the related one.
    new Array(3)        // [empty x 3] -- a length, not an element
    Array.of(3)         // [3]
Array.of
13
Which exists because new Array treats a single numeric argument specially.
new Array
14
What the interviewer is probing.1. "What makes something array-like?" Probing: the definition. Stalls: "It looks like an array." Moves up: it has a length and indexed properties but no array methods — arguments and a NodeList are the usual examples.
15
2. "What can Array.from do that spread cannot?" Probing: the difference. Stalls: "Nothing." Moves up: it converts array-like objects that are not iterable, and takes a mapping function as a second argument.
16
3. "How do you create a range?" Probing: the idiom. Stalls: "A for loop." Moves up: Array.from({ length: n }, (_, i) => i), which uses the length property and the map callback together.
17
4. "Why does Array(5).map not work as expected?" Probing: sparse arrays. Stalls: "It should." Moves up: the array has holes rather than undefined values, and map skips holes — Array.from or fill avoids it.