Spread- und Rest-Operator in JavaScript: Werte kopieren, zusammenführen und einsammeln

Drei Punkte, zwei Bedeutungen: Wie du mit dem Spread- und Rest-Operator Arrays und Objekte elegant kopierst, kombinierst und Funktionsargumente flexibel einsammelst.

Teilen

Manchmal steckt hinter einem winzigen Detail eine überraschend große Wirkung. In JavaScript sind das die drei Punkte .... Je nachdem, wo du sie einsetzt, bedeuten sie zwei völlig unterschiedliche Dinge: Der Spread-Operator packt die Inhalte einer Sammlung aus, der Rest-Operator sammelt einzelne Werte wieder ein. In diesem Beitrag schauen wir uns beide Seiten in Ruhe an – mit vielen kleinen, lauffähigen Beispielen, die du direkt in der Konsole ausprobieren kannst.

Spread: Sammlungen auspacken

Der Spread-Operator nimmt ein iterierbares Objekt – etwa ein Array – und „verteilt“ dessen Elemente an der Stelle, an der du ihn schreibst. Am deutlichsten wird das, wenn du zwei Arrays zusammenfügen willst, ohne concat zu bemühen:

const vorne = [1, 2, 3];
const hinten = [4, 5, 6];

const zusammen = [...vorne, ...hinten];
console.log(zusammen); // [1, 2, 3, 4, 5, 6]

// Du kannst auch einzelne Werte dazwischenschieben
const mitNull = [0, ...vorne, 3.5, ...hinten];
console.log(mitNull); // [0, 1, 2, 3, 3.5, 4, 5, 6]

Wichtig ist der Unterschied zwischen [...vorne, ...hinten] und [vorne, hinten]. Ohne die Punkte bekämst du ein verschachteltes Array [[1,2,3],[4,5,6]]. Der Spread-Operator löst die äußere Schicht auf und legt die einzelnen Elemente flach nebeneinander.

Kopieren statt referenzieren

Arrays und Objekte werden in JavaScript per Referenz weitergegeben. Wenn du eine Variable einfach einer anderen zuweist, zeigen beide auf dieselbe Sammlung – eine Änderung wirkt sich überall aus. Der Spread-Operator erstellt dagegen eine flache Kopie, mit der du gefahrlos arbeiten kannst:

const original = [10, 20, 30];

// Referenz: beide zeigen auf dasselbe Array
const referenz = original;
referenz.push(40);
console.log(original); // [10, 20, 30, 40] – ups!

// Kopie: unabhängig vom Original
const kopie = [...original];
kopie.push(99);
console.log(original); // [10, 20, 30, 40]
console.log(kopie);    // [10, 20, 30, 40, 99]

Genauso funktioniert das mit Objekten. Beim Kombinieren gilt: Spätere Eigenschaften überschreiben frühere – ideal, um Standardwerte mit Nutzerangaben zu überlagern:

const standard = { theme: "hell", schriftgroesse: 14, sprache: "de" };
const nutzer   = { schriftgroesse: 18 };

const einstellungen = { ...standard, ...nutzer };
console.log(einstellungen);
// { theme: "hell", schriftgroesse: 18, sprache: "de" }

Ein Wort der Vorsicht: Es ist eine flache Kopie. Verschachtelte Objekte oder Arrays bleiben weiterhin geteilte Referenzen. Wenn du { ...config } kopierst und config.optionen selbst ein Objekt ist, teilen sich Original und Kopie dieses innere Objekt.

Rest: Werte wieder einsammeln

Dieselben drei Punkte bedeuten das Gegenteil, sobald sie auf der linken Seite einer Zuweisung oder in einer Parameterliste stehen. Dort bündeln sie mehrere Werte zu einem einzigen Array. Besonders praktisch ist das beim Destructuring, wenn du die ersten Elemente einzeln herauslösen und den Rest zusammenhalten willst:

const [erster, zweiter, ...uebrige] = [1, 2, 3, 4, 5];

console.log(erster);  // 1
console.log(zweiter); // 2
console.log(uebrige); // [3, 4, 5]

// Auch bei Objekten: eine Eigenschaft herauslösen, den Rest behalten
const { passwort, ...oeffentlich } = {
  name: "Ada",
  email: "ada@example.com",
  passwort: "geheim",
};
console.log(oeffentlich); // { name: "Ada", email: "ada@example.com" }

Das letzte Beispiel ist ein hübsches Muster, um sensible Felder zu entfernen, bevor du ein Objekt weitergibst – etwa an eine API-Antwort.

Flexible Funktionen mit Rest-Parametern

Vor den Rest-Parametern musste man in Funktionen auf das etwas sperrige arguments-Objekt zurückgreifen. Heute schreibst du einfach ...zahlen und bekommst ein echtes Array, auf dem alle üblichen Methoden funktionieren:

function summe(...zahlen) {
  return zahlen.reduce((total, n) => total + n, 0);
}

console.log(summe(1, 2, 3));       // 6
console.log(summe(10, 20, 30, 40)); // 100
console.log(summe());               // 0

// Feste Parameter zuerst, der Rest sammelt den Überschuss ein
function begruessen(gruss, ...namen) {
  return namen.map((name) => `${gruss}, ${name}!`);
}
console.log(begruessen("Hallo", "Ben", "Mia"));
// ["Hallo, Ben!", "Hallo, Mia!"]

Der Rest-Parameter muss immer an letzter Stelle stehen – schließlich soll er alles Übrige aufnehmen. function f(...rest, letzter) ist ein Syntaxfehler.

Spread als Funktionsaufruf

Umgekehrt kannst du mit Spread ein Array wieder in einzelne Argumente auflösen. Das ersetzt das alte Function.prototype.apply und liest sich deutlich klarer:

const werte = [7, 2, 9, 4];

// Ohne Spread müsste man apply nutzen
console.log(Math.max(...werte)); // 9
console.log(Math.min(...werte)); // 2

// Auch praktisch, um einen String in einzelne Zeichen zu zerlegen
console.log([..."Hallo"]); // ["H", "a", "l", "l", "o"]

Weil Strings iterierbar sind, funktioniert Spread auch auf ihnen – ein kurzer Weg, um an ein Array einzelner Zeichen zu kommen, das sogar mit Emojis und mehrbyte-Zeichen korrekter umgeht als split("").

Fazit

Ob als Spread oder als Rest – die drei Punkte sind eines der ausdrucksstärksten Werkzeuge im modernen JavaScript. Merke dir die einfache Faustregel: Stehen sie dort, wo Werte verwendet werden (in einem Array-Literal, Objekt-Literal oder Funktionsaufruf), packen sie aus. Stehen sie dort, wo Werte empfangen werden (beim Destructuring oder in der Parameterliste), sammeln sie ein. Sobald dir dieser Unterschied in Fleisch und Blut übergegangen ist, schreibst du kürzeren, klareren Code – ganz ohne concat, apply oder das umständliche arguments-Objekt. Probier die Beispiele ruhig direkt in der Browser-Konsole aus, das prägt sich am schnellsten ein.