Der Spread-Operator ... ist eine der wirkungsvollsten Syntax-Ergänzungen aus ES2015. In Array-Literalen entpackt er ein Iterable in einzelne Elemente: [...a, ...b] kombiniert zwei Arrays, [...iter] materialisiert ein Iterable als Array, [...set] entfernt Duplikate. In Funktions-Aufrufen entpackt er ein Array als Argumente: Math.max(...nums). Er ersetzt damit viele ältere Patterns wie Array.prototype.slice.call(), apply() und concat(). Dieser Artikel zeigt die wichtigsten Anwendungs-Muster, klärt die Iterable-Voraussetzung und nennt die feinen Unterschiede zu concat() und Array.from().

Flache Kopie eines Arrays

Der häufigste Anwendungsfall: ein Array klonen, ohne dieselbe Referenz zu teilen.

JavaScript kopie.js
const original = [1, 2, 3];
const kopie = [...original];

kopie.push(4);
console.log(original); // [1, 2, 3] — unverändert
console.log(kopie);    // [1, 2, 3, 4]
console.log(original === kopie); // false — neue Referenz
Output
[ 1, 2, 3 ]
[ 1, 2, 3, 4 ]
false

Wichtig: flache Kopie. Verschachtelte Objekte werden per Referenz übernommen. Für Deep-Copy: structuredClone(arr) (ES2022).

JavaScript flache-kopie-grenze.js
const inner = { x: 1 };
const original = [inner];
const kopie = [...original];

// Innere Referenz geteilt
inner.x = 99;
console.log(kopie[0].x);   // 99 — Mutation propagiert
Output
99

Arrays kombinieren

[...a, ...b] ist die idiomatische Form von a.concat(b) — kürzer und besser lesbar.

JavaScript kombinieren.js
const a = [1, 2];
const b = [3, 4];

const kombiniert = [...a, ...b];
console.log(kombiniert);          // [1, 2, 3, 4]

// Beliebig viele Quellen
const c = [5];
const alles = [...a, ...b, ...c, 6, 7];
console.log(alles);               // [1, 2, 3, 4, 5, 6, 7]

// Mit Werten zwischendrin
const sandwich = [0, ...a, 'mitte', ...b, 'ende'];
console.log(sandwich);
Output
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5, 6, 7 ]
[ 0, 1, 2, 'mitte', 3, 4, 'ende' ]

Iterables entpacken — Set, Map, String, Generator

Spread nutzt das Iterator-Protokoll — alles, was iterable ist, lässt sich spreaden.

JavaScript iterables.js
// Set → Array (klassisches Dedup-Pattern)
const dedup = [...new Set([1, 2, 2, 3, 3, 3])];
console.log(dedup);                   // [1, 2, 3]

// String → Array von Codepoints
console.log([...'a😀b']);             // ['a', '😀', 'b']

// Map → Array von [key, value]-Tupeln
const m = new Map([['a', 1], ['b', 2]]);
console.log([...m]);                  // [['a', 1], ['b', 2]]

// Generator
function* gen() { yield 'x'; yield 'y'; yield 'z'; }
console.log([...gen()]);              // ['x', 'y', 'z']
Output
[ 1, 2, 3 ]
[ 'a', '😀', 'b' ]
[ [ 'a', 1 ], [ 'b', 2 ] ]
[ 'x', 'y', 'z' ]

Achtung: Plain-Objects sind nicht iterable. [...{a: 1}] wirft TypeError. Object-Spread {...obj} ist ein anderer Operator (Property-Enumeration, seit ES2018) — nicht zu verwechseln mit Array-Spread.

In Funktions-Aufrufen

Spread im Call-Site entpackt ein Array in einzelne Argumente.

JavaScript aufruf.js
const nums = [5, 1, 8, 3, 9, 2];

// Max/Min: erwarten einzelne Argumente
console.log(Math.max(...nums));   // 9
console.log(Math.min(...nums));   // 1

// Eigene Funktion
function summe(a, b, c) { return a + b + c; }
console.log(summe(...[10, 20, 30])); // 60

// Pre-ES2015 wäre das: Math.max.apply(null, nums)
Output
9
1
60

Spread ist nicht auf das erste Argument beschränkt — mehrere Spreads und feste Werte können beliebig gemischt werden:

JavaScript aufruf-mix.js
function f(a, b, c, d, e) {
    console.log(a, b, c, d, e);
}

const start = [1, 2];
const ende = [4, 5];
f(...start, 3, ...ende);
Output
1 2 3 4 5

Mit new — Constructor-Aufruf mit Spread

Spread funktioniert auch im new-Aufruf — das war vor ES2015 mit apply gar nicht möglich.

JavaScript new-spread.js
// Date-Konstruktor mit dynamischer Argument-Liste
const args = [2026, 4, 14];   // Jahr, Monat (0-basiert), Tag
const d = new Date(...args);
console.log(d.toISOString().slice(0, 10));

// Eigene Klasse
class Point {
    constructor(x, y, z) {
        this.x = x; this.y = y; this.z = z;
    }
}
const p = new Point(...[1, 2, 3]);
console.log(p);
Output
2026-05-14
Point { x: 1, y: 2, z: 3 }

Drei Wege im Vergleich

OperationSpread [...]concatArray.from
Echte Arrays kombinieren[...a, ...b]a.concat(b)nein
Set / String / Map / Genja, entpacktnein (als Element)ja, entpackt
Array-Like (HTMLCollection)nein (TypeError)neinja
Mit Mapperneinneinja, zweites Argument
Sparse Arrayfüllt mit undefinederhält Löchererhält Löcher
Lesbarkeit (kurz)sehr gutgutmittel

Faustregel: Spread für die meisten Fälle, Array.from für Array-Likes oder mit Mapper, concat nur in Spezialfällen (Sparse-Erhaltung, Symbol.isConcatSpreadable).

Spread vs. Rest — dieselbe Syntax, anderer Kontext

... heißt syntaktisch zwei verschiedene Dinge:

  • Spread: in einer Array/Object-Literal oder im Funktions-Aufruf → entpackt.
  • Rest: in einer Parameter-Liste oder Destructuring-Muster → sammelt.
JavaScript spread-vs-rest.js
// Spread (entpackt)
const arr = [...[1, 2, 3], 4, 5];
console.log(arr);                 // [1, 2, 3, 4, 5]

// Rest (sammelt) — in Parametern
function f(...args) {
    return args;
}
console.log(f(1, 2, 3));          // [1, 2, 3]

// Rest in Destructuring
const [erste, ...andere] = [10, 20, 30, 40];
console.log(erste, andere);       // 10 [20, 30, 40]
Output
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3 ]
10 [ 20, 30, 40 ]

Beide nutzen ... — der Kontext entscheidet, welche Operation gemeint ist.

Sparse-Arrays auffüllen

Wer ein sparse Array hat (z.B. von new Array(n)), kann Spread nutzen, um die Löcher zu undefined zu füllen:

JavaScript sparse-fuellen.js
const sparse = new Array(3);
console.log(0 in sparse);         // false — Loch

const dense = [...sparse];
console.log(0 in dense);          // true — undefined als echter Wert
console.log(dense);               // [undefined, undefined, undefined]
Output
false
true
[ undefined, undefined, undefined ]

Das ist ein subtiler aber wichtiger Unterschied — forEach/map/filter überspringen Löcher, aber durchlaufen undefined-Elemente.

Performance — bei großen Arrays

Spread ist generell etwas langsamer als concat bei sehr großen Quellen, weil es pro Quelle das Iterator-Protokoll durchläuft. Bei normalen Anwendungs-Daten (< 10.000 Elemente) unmessbar.

Bei extrem großen Argument-Listen (Math.max(...arr) mit Millionen Werten) gibt es eine harte Grenze: Engines haben einen Argument-Stack-Limit — Chrome/V8 etwa 65.536 Argumente, dann RangeError. Für solche Fälle ist eine manuelle Reduce-Schleife sicherer:

JavaScript grosse-arrays.js
// Bei sehr großen Arrays — Stack-Overflow möglich
// const max = Math.max(...riesigesArray);  // ggf. RangeError

// Sicherer:
function max(arr) {
    return arr.reduce((m, x) => x > m ? x : m, -Infinity);
}
console.log(max([5, 1, 8, 3, 9]));   // 9
Output
9

Interessantes

Spread basiert auf dem Iterator-Protokoll

Alles, was Symbol.iterator implementiert, lässt sich spreaden. Daher: Array, Set, Map, String, Generator, NodeList. NICHT: Plain-Object, HTMLCollection, Number. Bei Versuch: TypeError: x is not iterable.

Object-Spread {...obj} ist eine andere Operation

{...obj} nutzt nicht das Iterator-Protokoll, sondern own enumerable Properties. Ist seit ES2018 spezifiziert. Daher: [...obj] wirft TypeError für Plain-Objects, {...obj} klappt. Verwirrend, aber gewollt.

Spread im new-Call: nur dank ES2015

new Klasse(...args) war Pre-ES2015 schwer zu implementieren. Function.prototype.apply funktioniert nicht mit new. Workaround damals: Object.create(Klasse.prototype) + manueller Constructor-Aufruf — hässlich. Spread löst das elegant.

Spread füllt Löcher mit undefined, concat erhält sie

[...[1, , 3]] liefert [1, undefined, 3] — Loch wurde gefüllt. [1, , 3].concat() erhält das Loch. In modernem Code irrelevant (sparse Arrays selten), aber bei Legacy-Code mit new Array(n) wichtig.

Dedup-Pattern: [...new Set(arr)]

Die idiomatische Form, Duplikate aus einem Array zu entfernen: [...new Set(arr)]. Set erlaubt keine Duplikate, Spread entpackt es zurück in ein Array. Funktioniert für primitives nahezu perfekt. Bei Object-Werten greift Reference-Equality — gleiche Werte aus verschiedenen Refs werden NICHT als Duplikat erkannt.

Spread vs. Math.max-Limit — RangeError bei zu vielen Argumenten

Math.max(...riesigesArray) wirft bei sehr großen Arrays (V8 ab ~65k Argumenten) einen RangeError: Maximum call stack size exceeded. Für massive Datenmengen: arr.reduce nutzen.

Spread in JSX/Templates für Props-Forwarding

In React: <Component {...props} /> spreaded ein Props-Object in die Component. In Vue/JSX ähnlich. Das ist Object-Spread (nicht Array-Spread), aber dieselbe Syntax. Sehr verbreitet beim Decorator-Pattern.

Mehrfaches Spread ist günstig, mehrfaches concat nicht

[...a, ...b, ...c, ...d] baut das Ergebnis in einer Pass — Engine optimiert. a.concat(b).concat(c).concat(d) würde mehrere Zwischen-Arrays allokieren. Bei massiven Daten messbar; bei normalem Code unwichtig.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Arrays

Zur Übersicht