Array.prototype.reverse() kehrt die Reihenfolge der Elemente eines Arrays in-place um — also direkt am Original-Array, ohne neue Kopie. Die Methode liefert eine Referenz auf das gleiche Array zurück, das jetzt umgekehrt ist. Genau diese Mutation ist die Hauptfalle: gemeinsame Datenstrukturen werden unerwartet verändert, und Funktionen, die wie reine Aufrufer aussehen, haben Seiteneffekte. Seit ES2023 gibt es mit Array.prototype.toReversed() die immutable Variante, die das Original unangetastet lässt und ein neues Array zurückgibt — fast immer die bessere Wahl in modernem Code.
Signatur & Grundform
arr.reverse(): typeof arr // mutiert arr in-place, liefert arrKeine Argumente. Rückgabewert ist dasselbe Array wie der Eingang — nicht eine Kopie, sondern eine Referenz auf das mutierte Original.
const zahlen = [1, 2, 3, 4, 5];
const ergebnis = zahlen.reverse();
console.log(zahlen); // [5, 4, 3, 2, 1] — mutiert!
console.log(ergebnis); // [5, 4, 3, 2, 1]
console.log(zahlen === ergebnis); // true — identische Referenz[ 5, 4, 3, 2, 1 ]
[ 5, 4, 3, 2, 1 ]
trueDas Identitäts-Detail ist relevant: ein if (arr === reversed)-Check liefert immer true — beide zeigen auf dasselbe Object.
Mutation als Falle
In gemeinsam genutzten Datenstrukturen schlägt die Mutation oft unerwartet zu.
const original = ['a', 'b', 'c'];
function letzteZuerst(arr) {
return arr.reverse(); // Bug: mutiert das übergebene Array
}
const ausgabe = letzteZuerst(original);
console.log(ausgabe); // ['c', 'b', 'a']
console.log(original); // ['c', 'b', 'a'] — auch geändert![ 'c', 'b', 'a' ]
[ 'c', 'b', 'a' ]Eine Funktion, die nur Werte sortieren/zurückgeben soll, hat hier einen versteckten Seiteneffekt. Der saubere Fix: vor reverse() eine Kopie ziehen.
const original = ['a', 'b', 'c'];
// Variante 1: Spread-Kopie
const r1 = [...original].reverse();
// Variante 2: slice() ohne Argumente liefert flache Kopie
const r2 = original.slice().reverse();
// Variante 3: ES2023 toReversed() — immutable
const r3 = original.toReversed();
console.log(original); // ['a', 'b', 'c'] — unverändert
console.log(r1, r2, r3);[ 'a', 'b', 'c' ]
[ 'c', 'b', 'a' ] [ 'c', 'b', 'a' ] [ 'c', 'b', 'a' ]toReversed() — die immutable Variante (ES2023)
Mit ES2023 hat JavaScript vier neue Change-Array-by-Copy-Methoden bekommen, darunter toReversed(). Sie verhält sich semantisch wie reverse(), lässt aber das Original unverändert und liefert ein neues Array.
const original = [1, 2, 3, 4, 5];
const rev = original.toReversed();
console.log(original); // [1, 2, 3, 4, 5] — unverändert
console.log(rev); // [5, 4, 3, 2, 1]
console.log(original === rev); // false — neue Referenz[ 1, 2, 3, 4, 5 ]
[ 5, 4, 3, 2, 1 ]
falseBrowser-Support: Chrome 110+, Firefox 115+, Safari 16+, Node 20+ — Baseline „widely available" seit Mid-2024. Für noch ältere Targets ein simpler Polyfill:
if (!Array.prototype.toReversed) {
Array.prototype.toReversed = function() {
return this.slice().reverse();
};
}In Code, der frische Arrays produziert (z.B. nach filter/map), kann man weiterhin reverse() direkt anhängen — das mutiert die Zwischen-Kopie, nicht das Original-Array.
String umkehren — der bekannte Trick
Strings haben keine eigene reverse()-Methode. Der idiomatische Trick: in ein Array zerlegen, umkehren, zurück zu String joinen.
const wort = 'JavaScript';
const ruekwaerts = wort.split('').reverse().join('');
console.log(ruekwaerts); // 'tpircSavaJ'
// Achtung bei Emojis / Surrogate-Pairs:
const mitEmoji = 'Hi 😀';
console.log(mitEmoji.split('').reverse().join(''));
// → ' 😀iH' — wird oft mit ersetzten Replacement-Chars angezeigt
// Korrekt mit Codepoint-Iteration:
const sauber = [...mitEmoji].reverse().join('');
console.log(sauber); // '😀 iH'tpircSavaJ
😀iH
😀 iHsplit('') zerlegt nach UTF-16-Code-Units — Surrogate-Pairs (Emojis, manche CJK-Zeichen) werden zerstört. Der Spread-Operator auf einem String nutzt das Iterator-Protokoll und liefert ganze Codepoints — das ist die Unicode-saubere Variante.
Sparse Arrays — leere Slots
Bei sparse Arrays (Arrays mit „Löchern", [1, , , 4]) erhält reverse() die Lücken-Positionen, nicht die Werte daran:
const sparse = [1, , , 4];
console.log(sparse.length); // 4
console.log(0 in sparse); // true
console.log(1 in sparse); // false — Loch
sparse.reverse();
console.log(sparse); // [4, <2 empty items>, 1]
console.log(0 in sparse); // true
console.log(1 in sparse); // false — Loch erhalten, an neuer Position4
true
false
[ 4, <2 empty items>, 1 ]
true
falseIn modernem Code sind sparse Arrays selten — sie entstehen meist nur durch new Array(n) oder explizite delete arr[i]-Operationen.
Typed Arrays — eigene reverse-Variante
Int8Array, Uint8Array, Float32Array usw. haben ihre eigene reverse()-Methode mit identischer Semantik (in-place, gleiche Referenz zurück). Auch hier gibt es seit ES2023 toReversed().
const ints = new Int32Array([10, 20, 30, 40]);
ints.reverse();
console.log(Array.from(ints)); // [40, 30, 20, 10]
const original = new Uint8Array([1, 2, 3]);
const kopie = original.toReversed();
console.log(Array.from(original)); // [1, 2, 3] — unberührt
console.log(Array.from(kopie)); // [3, 2, 1][ 40, 30, 20, 10 ]
[ 1, 2, 3 ]
[ 3, 2, 1 ]reverse() am Ende einer Pipeline
In filter/map-Pipelines ist reverse() praktisch — das Zwischen-Array ist sowieso eine Kopie, die Mutation ist daher unkritisch.
const ergebnisse = [
{ name: 'A', punkte: 10 },
{ name: 'B', punkte: 30 },
{ name: 'C', punkte: 20 },
];
// Klassisch: kopieren, sortieren, umkehren
const absteigend = ergebnisse
.map(e => e.punkte)
.sort((a, b) => a - b)
.reverse(); // Zwischen-Array von map/sort, daher safe
console.log(absteigend); // [30, 20, 10]
// Direkter wäre: .sort((a, b) => b - a) — keine Umkehrung nötig[ 30, 20, 10 ]Für absteigende Sortierung ist der Vergleichs-Funktion-Trick (b - a) idiomatischer als sort().reverse().
Performance
reverse() ist O(n) — die Engine geht einmal durch das Array und vertauscht Elemente von außen nach innen. toReversed() ist ebenfalls O(n), allokiert aber ein neues Array.
Bei sehr großen Arrays (> 100.000 Elemente) und Hot-Pfaden ist der Unterschied in Memory-Pressure messbar — reverse() braucht keine zusätzliche Allokation, ist daher GC-freundlicher. In normalem Anwendungs-Code unerheblich; Lesbarkeit und Bug-Sicherheit sind die wichtigeren Kriterien.
Welche Form nehmen?
| Situation | Empfehlung |
|---|---|
| Original soll erhalten bleiben | arr.toReversed() (ES2023) |
| Vor ES2023-Targets | arr.slice().reverse() |
In map/filter-Pipeline | direkt .reverse() (Zwischen-Array) |
| Absteigend sortieren | arr.sort((a, b) => b - a) |
| Array darf mutiert werden | arr.reverse() direkt |
| Immutable-Reducer (Redux, React-State) | arr.toReversed() Pflicht |
Häufige Stolperfallen
reverse() mutiert — das Original ist hinterher umgekehrt
Der häufigste Anfänger-Fehler: const rev = arr.reverse(); mit der Annahme, dass arr unangetastet bleibt. Falsch: arr und rev zeigen auf dasselbe (umgekehrte) Array. Lösung: toReversed() oder [...arr].reverse() für saubere Trennung.
Rückgabewert ist dieselbe Referenz, nicht eine Kopie
arr.reverse() === arr ist immer true. Wer das nicht weiß und beide Variablen weiterführt, denkt manchmal, er hätte zwei verschiedene Arrays — und wundert sich, dass Änderungen an dem einen das andere mitbetreffen.
In React-State niemals reverse() — der Render bekommt nichts mit
React vergleicht State per Reference-Identity. setItems(items.reverse()) übergibt dieselbe Referenz wie vorher — React sieht „kein Update", rendert nicht neu. Korrekt: setItems(items.toReversed()) oder setItems([...items].reverse()) — neue Referenz, neues Rendering.
Strings haben kein reverse() — split + reverse + join
'abc'.reverse() ist TypeError. Die idiomatische Form: str.split('').reverse().join(''). Bei Unicode-Strings mit Emojis: [...str].reverse().join('') nutzen, das iteriert pro Codepoint.
Surrogate-Pairs werden durch split('') zerstört
Ein Emoji wie '😀' ist UTF-16 zwei Code-Units (Surrogate-Pair). split('') trennt die zwei Hälften — beim Reverse + Join kommt unleserlicher Zeichenmüll heraus. Array.from(str) oder [...str] nutzen das Iterator-Protokoll und respektieren Codepoint-Grenzen.
sort().reverse() statt sort((a, b) => b - a)
Beides liefert absteigende Sortierung. sort((a, b) => b - a) ist O(n log n), sort().reverse() ist O(n log n) + O(n) — also etwas langsamer. Wichtiger: die Compare-Funktion-Variante ist expliziter und vermeidet die Doppel-Mutation-Falle.
toReversed seit ES2023 — Baseline-Status
Seit Mid-2024 als „widely available" im Web-Baseline. Chrome 110, Firefox 115, Safari 16, Node 20 — alle modernen Targets. Ein Polyfill ist trivial: function toReversed() { return this.slice().reverse(); }.
Sparse Arrays erhalten ihre Löcher bei reverse()
[1, , , 4].reverse() liefert [4, <empty>, <empty>, 1] — die Löcher wandern, aber bleiben Löcher. in-Operator zeigt das: 1 in arr ist false. In modernem Code irrelevant, weil sparse Arrays selten sind — bei Legacy-Code mit new Array(n) aber relevant.
Weiterführende Ressourcen
Externe Quellen
- Array.prototype.reverse() – MDN
- Array.prototype.toReversed() – MDN
- Array.prototype.reverse – ECMAScript Spec
- Change Array by Copy – TC39 Proposal
- Baseline 2023 – web.dev