JavaScript Rest- und Spread-Syntax
Rest-Parameter und Spread-Syntax sind zwei ES6-Features in JavaScript, die Eleganz und Effizienz beim Umgang mit Argumenten und Datenstrukturen bieten.
In JavaScript erfüllt das Drei-Punkte-Token ... zwei entgegengesetzte Aufgaben, je nachdem, wo es geschrieben wird. Als Funktionsparameter sammelt es viele Argumente in einem einzigen array — das ist ein Rest-Parameter. Überall sonst verteilt es ein iterierbares Objekt oder ein object in seine einzelnen Bestandteile — das ist die Spread-Syntax. Dasselbe Symbol, spiegelbildliche Bedeutung.
Beide wurden in ES6 (2015) eingeführt. Diese Seite behandelt Rest-Parameter (einschließlich der Regel, dass sie am Ende stehen müssen), Spread in Funktionsaufrufen, array-Literalen und object-Literalen, das Kopieren und Zusammenführen mit Spread, die Unterschiede zwischen Rest und Spread sowie die Vorteile gegenüber dem alten arguments-object.
Rest-Parameter in JavaScript verstehen
Ein Rest-Parameter ermöglicht es einer Funktion, eine unbegrenzte Anzahl von Argumenten zu akzeptieren und sie als echtes array zu empfangen. Man schreibt ... gefolgt von einem Namen; dieser Name wird zu einem array, das alle Argumente enthält, die nicht von einem früheren Parameter abgeglichen wurden.
Syntax und Verwendung
Im folgenden Beispiel ist numbers ein gewöhnliches array, sodass man array-Methoden wie reduce direkt darauf aufrufen kann — ohne Konvertierung.
Der Rest-Parameter muss zuletzt stehen
Eine Funktion kann nur einen Rest-Parameter haben, und er muss der letzte in der Parameterliste sein. Benannte Parameter davor werden zuerst befüllt; der Rest-Parameter sammelt dann alles, was übrig bleibt. Ihn an anderer Stelle zu platzieren führt zu einem SyntaxError.
Vorteile gegenüber dem arguments-object
Vor ES6 war das spezielle arguments-object, das innerhalb von Nicht-Pfeilfunktionen verfügbar ist, die einzige Möglichkeit, alle Argumente zu lesen. Rest-Parameter sind in fast jeder Hinsicht besser:
- Ein echtes array.
argumentsist array-ähnlich (es hat einelengthund Indizes), aber es fehlenmap,filter,reduceusw. Ein Rest-Parameter ist ein echtes array. - Explizit und lesbar. Die Signatur
function sum(...numbers)zeigt dem Leser, dass die Funktion eine variable Anzahl von Werten erwartet.argumentsist in der Signatur unsichtbar. - Nur die Extras benennen. Feste Parameter können mit einem Rest-Parameter kombiniert werden, wie oben gezeigt —
argumentsenthält immer alle Argumente, einschließlich der bereits benannten. - Funktioniert mit Pfeilfunktionen. Pfeilfunktionen haben kein eigenes
arguments-object, daher ist ein Rest-Parameter die einzige Möglichkeit, variable Argumente in einer Pfeilfunktion zu sammeln.
Die Spread-Syntax im Detail
Die Spread-Syntax erweitert ein iterierbares Objekt — ein array, einen string, ein Set, eine Map oder ein beliebiges Iterable — an jeder Stelle, an der eine Liste von Werten erwartet wird, in seine einzelnen Elemente. Die drei Kontexte, in denen sie verwendet wird, sind Funktionsaufrufe, array-Literale und object-Literale.
Spread in array-Literalen
Innerhalb von [ ] fügt Spread jedes Element eines Iterables in das neue array ein. Dies ist die sauberste Methode, ein array an beliebiger Position in ein anderes einzufügen:
Da strings iterierbar sind, erzeugt das Spreaden eines strings ein array seiner Zeichen:
Spread in Funktionsaufrufen
In einem Funktionsaufruf wandelt Spread ein array wieder in eine Liste separater Argumente um. Dies ersetzt das alte Muster func.apply(null, array):
Spread in object-Literalen
Innerhalb von { } kopiert Spread die eigenen aufzählbaren Eigenschaften eines objects in ein neues object. Bei Schlüsselkollisionen gewinnt der spätere Wert — das macht Spread ideal für das Anwenden von Überschreibungen oder Standardwerten:
Kopieren und Zusammenführen
Spread ist der idiomatische Weg, eine flache Kopie zu erstellen oder Sammlungen zusammenzuführen, ohne die Originale zu verändern:
Spread ist flach. Es werden nur Werte der obersten Ebene kopiert. Verschachtelte objects und arrays werden weiterhin per Referenz geteilt, sodass das Mutieren eines verschachtelten Werts beide Kopien betrifft:
Rest vs. Spread: Die Unterschiede erkennen
Das Token ... sieht in beiden Rollen identisch aus, daher sollte man die Position nutzen, um zu entscheiden, was man gerade liest:
| Rest-Parameter | Spread-Syntax | |
|---|---|---|
| Wo es erscheint | In der Parameterliste einer Funktion | In einem Aufruf, array-Literal oder object-Literal |
| Was es tut | Sammelt viele Werte in einem array | Verteilt ein Iterable/object in viele Werte |
Seite des = | Linke Seite (ein Destructuring-Ziel) | Rechte Seite (ein erzeugter Wert) |
| Beispiel | function f(...args) {} | f(...args) |
Ein einfacher Test: Wenn ...x Werte empfängt, ist es Rest; wenn es Werte produziert, ist es Spread.
Rest-Parameter und Spread-Syntax kombinieren
Die beiden sind Spiegelbilder, sodass sie sich natürlich ergänzen — Rest sammelt Argumente auf dem Weg hinein in ein array, und Spread erweitert ein array auf dem Weg hinaus wieder in Argumente:
Ein häufiges Muster in der Praxis ist ein Wrapper, der alle Argumente an eine andere Funktion weiterleitet:
Destructuring mit dem Rest-Muster
Bei einer Destructuring-Zuweisung erfasst das Rest-Muster alle Eigenschaften oder Elemente, die nicht explizit benannt wurden. Bei objects erzeugt es ein object der verbleibenden Schlüssel; bei arrays ein array der übrigen Elemente.
Fazit
Das Token ... ist eine der nützlichsten Ergänzungen, die ES6 zu JavaScript gebracht hat. Als Rest-Parameter sammelt es eine variable Anzahl von Argumenten in einem übersichtlichen array (und ersetzt das umständliche arguments-object); als Spread-Syntax verteilt es Iterables in Funktionsaufrufe, array-Literale und object-Literale und ermöglicht prägnante flache Kopien und Zusammenführungen. Zwei Regeln sollte man dabei im Hinterkopf behalten: Ein Rest-Parameter muss der letzte Parameter sein, und Spread-Kopien sind flach.
Verwandte Themen
- Destructuring-Zuweisung — Werte aus arrays und objects extrahieren, häufig in Kombination mit dem Rest-Muster.
- JavaScript Array — die Datenstruktur, die Rest-Parameter liefern und Spread erweitert.
- Pfeilfunktionen im Detail — warum Pfeilfunktionen auf Rest-Parameter statt
argumentsangewiesen sind. - Funktions-Binding —
thiskontrollieren, häufig in Kombination mit Spread beim Weiterleiten von Argumenten.