MWCodebymw.de ↗
JavaScript

toSorted, toReversed und with: Arrays sortieren, ohne das Original zu zerstören

array.sort() sortiert nicht eine Kopie, sondern das Array selbst – und genau daran ist schon mancher Zustand im Frontend stillschweigend kaputtgegangen. Seit ES2023 gibt es zu jeder dieser Methoden eine Variante, die eine Kopie zurückgibt.

Der Fehler sieht harmlos aus:

function teuersteZuerst(produkte) {
  return produkte.sort((a, b) => b.preis - a.preis);
}

Die Funktion gibt zwar eine sortierte Liste zurück – aber sie sortiert dabei die übergebene Liste selbst um. Wer danach produkte in der ursprünglichen Reihenfolge braucht, bekommt sie nicht mehr. In einem Framework, das seinen Zustand mit dem vorherigen vergleicht, ist der Effekt noch unangenehmer: Vorher und Nachher sind dasselbe Objekt, also „hat sich nichts geändert", und die Oberfläche zeichnet nicht neu.

Seit ES2023 gibt es zu den vier verändernden Array-Methoden je eine, die stattdessen eine Kopie liefert.

Die vier neuen Methoden

const preise = [30, 5, 12];

preise.toSorted((a, b) => a - b);   // [5, 12, 30]   – neues Array
preise.toReversed();                // [12, 5, 30]   – neues Array
preise.with(1, 99);                 // [30, 99, 12]  – ein Feld ersetzt
preise.toSpliced(1, 1);             // [30, 12]      – ein Feld entfernt

console.log(preise);                // [30, 5, 12]  ← unverändert

| verändert das Original | gibt eine Kopie zurück | |---|---| | sort() | toSorted() | | reverse() | toReversed() | | arr[i] = x | with(i, x) | | splice() | toSpliced() |

Die Funktion von oben wird damit zu einer, die hält, was ihr Name verspricht:

const teuersteZuerst = (produkte) => produkte.toSorted((a, b) => b.preis - a.preis);

Drei Dinge, die dich sonst erwischen

toSorted() ohne Vergleichsfunktion sortiert wie Text. Genau wie sort(). [30, 5, 12] wird zu [12, 30, 5], weil "12" vor "30" vor "5" kommt. Bei Zahlen gehört die Vergleichsfunktion also weiterhin dazu – die neue Methode ändert daran nichts.

Die Kopie ist flach. Das neue Array ist neu, die Objekte darin sind dieselben. Änderst du kopie[0].name, ändert sich auch original[0].name. Willst du wirklich alles lösen, brauchst du structuredClone.

with() wirft bei einem Index außerhalb der Liste. [1, 2].with(5, 0) ergibt einen RangeError und nicht etwa stillschweigend ein Loch – das ist gut so, macht aber aus einer Zuweisung eine Stelle, an der man auf den Index achten muss. Negative Indizes zählen wie überall von hinten: .with(-1, 0) ersetzt das letzte Feld.

Wo ich das benutze

Überall dort, wo eine Liste angezeigt wird und die Sortierung nur die Ansicht betrifft: eine Tabelle, die man nach Spalten sortieren kann, eine Bestenliste, ein Stapel Karten. Der Zustand bleibt, wie er ist, und die Anzeige bekommt ihre eigene Reihenfolge. Das spart genau die Sorte Fehler, die man erst drei Klicks später bemerkt – und dann lange sucht.

Unterstützt wird das von allen aktuellen Browsern und ab Node 20. Wenn du noch ältere Umgebungen bedienen musst, tut es [...arr].sort(...) genauso; die neuen Methoden sagen nur deutlicher, was gemeint ist.

Mehr solcher Kleinigkeiten, die im Alltag Zeit sparen, sammle ich laufend auf code.bymw.de – schau gern regelmäßig vorbei.

Quellen

#Arrays#ES2023#toSorted#Unveränderlichkeit#JavaScript

Du brauchst mehr als ein Snippet?

Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.

Projekt anfragen →