Array.from() ist die universale Brücke von iterierbaren und array-like Objekten zu echten Arrays. Sie nimmt eine Quelle plus optional einen Mapper-Callback und liefert ein neues Array. Iterables sind alle Strukturen mit Symbol.iterator (String, Set, Map, NodeList, Generator). Array-likes sind Objekte mit length-Property und nummerischen Keys (arguments, manche DOM-Collections). Mit dem { length: n }-Trick lässt sich auch ein synthetisches Array fester Länge erzeugen — sehr praktisch zur Initialisierung. Seit ES2024 gibt es Array.fromAsync() für AsyncIterables.
Signatur
Array.from(source, mapFn?, thisArg?): Array- source: ein Iterable oder Array-Like
- mapFn: optionaler Callback
(element, index) => neu - thisArg: optional,
this-Wert für den Mapper
// Iterable: Set → Array
console.log(Array.from(new Set([1, 2, 2, 3]))); // [1, 2, 3]
// Iterable: String → Array von Codepoints
console.log(Array.from('abc')); // ['a', 'b', 'c']
// Array-like: arguments → Array
function f() { return Array.from(arguments); }
console.log(f(10, 20, 30)); // [10, 20, 30]
// Mit Mapper
console.log(Array.from([1, 2, 3], x => x * 10)); // [10, 20, 30][ 1, 2, 3 ]
[ 'a', 'b', 'c' ]
[ 10, 20, 30 ]
[ 10, 20, 30 ]Iterable vs. Array-Like
Zwei verschiedene Protokolle — beide funktionieren mit Array.from().
// ITERABLE: hat Symbol.iterator
const iterable = {
*[Symbol.iterator]() {
yield 'a';
yield 'b';
yield 'c';
},
};
console.log(Array.from(iterable)); // ['a', 'b', 'c']
// ARRAY-LIKE: hat length + numerische Keys
const arrayLike = { 0: 'x', 1: 'y', 2: 'z', length: 3 };
console.log(Array.from(arrayLike)); // ['x', 'y', 'z']
// arguments ist beides — Array-Like UND iterable
function f() {
console.log(Array.from(arguments));
}
f(1, 2, 3);[ 'a', 'b', 'c' ]
[ 'x', 'y', 'z' ]
[ 1, 2, 3 ]Array.from prüft zuerst auf Symbol.iterator — wenn vorhanden, nutzt es das Iterator-Protokoll. Sonst fällt es auf length + Index-Zugriff zurück.
Der { length: n }-Trick
Ein Objekt mit nur einer length-Property ist ein gültiges Array-Like. Array.from durchläuft Index 0 bis n-1 und liest dort — die Properties existieren nicht, also undefined.
// Array fester Länge mit undefined (kein sparse!)
const undefArr = Array.from({ length: 3 });
console.log(undefArr); // [undefined, undefined, undefined]
console.log(0 in undefArr); // true — echtes Element, kein Loch!
// Mit Mapper: 1..5
const zahlen = Array.from({ length: 5 }, (_, i) => i + 1);
console.log(zahlen); // [1, 2, 3, 4, 5]
// Pro Position eine neue Objekt-Instanz
const matrix = Array.from({ length: 3 }, () => []);
matrix[0].push('A');
console.log(matrix); // [['A'], [], []][ undefined, undefined, undefined ]
true
[ 1, 2, 3, 4, 5 ]
[ [ 'A' ], [], [] ]Dieses Pattern ist die idiomatische Form, ein Array bestimmter Länge mit dynamisch berechneten Werten zu initialisieren — und vermeidet die Sparse-Falle von new Array(n).
Mapper inline vs. .map() nachträglich
Array.from(src, mapFn) ist semantisch nahe an Array.from(src).map(mapFn), aber effizienter — in einem Schritt statt zwei Arrays nacheinander.
const set = new Set([1, 2, 3]);
// Zwei Arrays werden allokiert
const a = Array.from(set).map(x => x * 2);
// Ein Array — kombinierte Iteration
const b = Array.from(set, x => x * 2);
console.log(a); // [2, 4, 6]
console.log(b); // [2, 4, 6][ 2, 4, 6 ]
[ 2, 4, 6 ]Bei sehr großen Quellen lohnt die Inline-Form. Bei kleinen Datenmengen ist die .map()-Form oft lesbarer, weil die zwei Schritte klarer getrennt sind.
Array.from() vs. Spread [...iter]
Beide erzeugen ein Array aus einem Iterable. Unterschiede:
const set = new Set([1, 2, 3]);
// Beide identisch bei Iterables
console.log(Array.from(set)); // [1, 2, 3]
console.log([...set]); // [1, 2, 3]
// Aber: Array-Likes funktionieren NUR mit Array.from
const al = { 0: 'a', 1: 'b', length: 2 };
console.log(Array.from(al)); // ['a', 'b']
try {
console.log([...al]); // TypeError: al is not iterable
} catch (e) {
console.log('Spread:', e.message);
}
// Array.from akzeptiert einen Mapper, Spread nicht
console.log(Array.from(set, x => x * 10)); // [10, 20, 30][ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 'a', 'b' ]
Spread: al is not iterable
[ 10, 20, 30 ]Faustregel: bei Iterables ist Spread kürzer ([...iter]). Bei Array-Likes oder mit Mapper braucht's Array.from.
DOM-Beispiel — NodeList in echtes Array
Die häufigste Real-World-Anwendung im Browser: eine NodeList (z.B. von querySelectorAll) in ein echtes Array konvertieren, damit map/filter/reduce darauf funktionieren.
// Direkt: liefert NodeList, kein echtes Array
const buttons = document.querySelectorAll('button');
// In Array konvertieren — Mapper inline
const buttonTexte = Array.from(buttons, b => b.textContent);
// Filter funktioniert dann
const aktive = Array.from(buttons).filter(b => !b.disabled);
// Spread funktioniert auch — NodeList ist seit modernen Browsern iterable
const alt = [...buttons];NodeList ist seit ES2015 iterable — Spread und for-of funktionieren. HTMLCollection (von getElementsByTagName) ist nicht iterable — da hilft nur Array.from.
Bereiche und Sequenzen erzeugen
Mit dem length-Trick und einem Mapper lassen sich beliebige numerische Sequenzen in einer Zeile bauen.
// Zahlen 1..10
const r1 = Array.from({ length: 10 }, (_, i) => i + 1);
console.log(r1);
// Zahlen 0, 2, 4, ..., 18
const r2 = Array.from({ length: 10 }, (_, i) => i * 2);
console.log(r2);
// Quadrate
const r3 = Array.from({ length: 5 }, (_, i) => i * i);
console.log(r3);
// Zufalls-Floats
const r4 = Array.from({ length: 5 }, () => Math.random().toFixed(2));
console.log(r4);[
1, 2, 3, 4, 5,
6, 7, 8, 9, 10
]
[
0, 2, 4, 6, 8,
10, 12, 14, 16, 18
]
[ 0, 1, 4, 9, 16 ]
[ '0.18', '0.71', '0.42', '0.96', '0.23' ]Pre-ES2015 hätte man dafür eine for-Schleife geschrieben. Mit Array.from reicht eine Zeile.
Array.fromAsync() — asynchrone Variante (ES2024)
Seit ES2024 gibt es das asynchrone Pendant für AsyncIterables (Streams, async Generators).
async function* asyncRange(n) {
for (let i = 0; i < n; i++) {
await new Promise(r => setTimeout(r, 5));
yield i;
}
}
(async () => {
const arr = await Array.fromAsync(asyncRange(5));
console.log(arr); // [0, 1, 2, 3, 4]
// Mit Mapper
const arr2 = await Array.fromAsync(asyncRange(3), x => x * 100);
console.log(arr2); // [0, 100, 200]
})();[ 0, 1, 2, 3, 4 ]
[ 0, 100, 200 ]Browser-Support: Chrome 121+, Firefox 115+, Safari 16.4+, Node 22+ — Baseline 2024. Davor: manueller Loop mit for-await-of.
Interessantes
Iterables und Array-Likes — zwei Protokolle, eine Methode
Array.from testet zuerst auf Symbol.iterator (Iterable-Protokoll). Fehlt das, fällt es auf length + Index-Zugriff zurück (Array-Like-Protokoll). Spread [...x] kennt nur das Iterable-Protokoll, daher die Lücke bei reinen Array-Likes.
length-Trick erzeugt undefined-gefülltes Array, kein sparse
Array.from({length: 3}) liefert [undefined, undefined, undefined] — echte Elemente, kein Loch. new Array(3) liefert [<3 empty items>] — sparse mit Löchern. Wer mit map/filter darauf operieren will, muss Array.from nutzen.
Inline-Mapper ist effizienter als .map() danach
Array.from(src, fn) allokiert ein Array, Array.from(src).map(fn) allokiert zwei. Bei großen Quellen messbar. Bei kleinen wurst — Lesbarkeit entscheidet.
String → Array iteriert pro Codepoint, nicht Code-Unit
Array.from('a😀b') liefert ['a', '😀', 'b'] — drei Elemente, Surrogate-Pairs korrekt zusammengehalten. 'a😀b'.split('') würde die zwei UTF-16-Units des Emojis trennen — vier Elemente, davon zwei kaputt.
Mapper hat zweites Argument: index
Der Mapper-Callback bekommt (value, index) — wie bei Array.prototype.map. Das ist die Basis für den length-Trick: (_, i) => i + 1 nutzt nur den Index, ignoriert den (undefined-)Wert.
Set wird durch Array.from de-dupliziert? Nein — Set IST schon dedupliziert
Array.from(new Set([1, 2, 2, 3])) liefert [1, 2, 3] — nicht weil Array.from dedupliziert, sondern weil das Set selbst keine Duplikate erlaubt. Das macht Set + Array.from zum idiomatischen Dedup-Pattern: Array.from(new Set(arr)).
HTMLCollection ist NICHT iterable — Array.from nötig
document.getElementsByTagName('div') liefert eine HTMLCollection. Sie ist Array-Like (length + Index), aber NICHT iterable (kein Symbol.iterator). Daher: [...col] schlägt fehl, Array.from(col) klappt. NodeList dagegen ist iterable.
Array.fromAsync seit ES2024 — Baseline 2024
Die asynchrone Variante akzeptiert AsyncIterables und synchrone Iterables, deren Werte Promises sein können. Im Inline-Mapper kann ebenfalls await stehen. Praktisch für Stream-Pipelines (Web Streams, async generators).
Weiterführende Ressourcen
Externe Quellen
- Array.from() – MDN
- Array.fromAsync() – MDN
- Iteration protocols – MDN
- Array.from – ECMAScript Spec
- TC39 Proposal: Array.fromAsync