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

JavaScript signatur.js
arr.reverse(): typeof arr   // mutiert arr in-place, liefert arr

Keine Argumente. Rückgabewert ist dasselbe Array wie der Eingang — nicht eine Kopie, sondern eine Referenz auf das mutierte Original.

JavaScript grundform.js
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
Output
[ 5, 4, 3, 2, 1 ]
[ 5, 4, 3, 2, 1 ]
true

Das 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.

JavaScript mutation-falle.js
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!
Output
[ '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.

JavaScript mutation-vermieden.js
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);
Output
[ '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.

JavaScript toreversed.js
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
Output
[ 1, 2, 3, 4, 5 ]
[ 5, 4, 3, 2, 1 ]
false

Browser-Support: Chrome 110+, Firefox 115+, Safari 16+, Node 20+ — Baseline „widely available" seit Mid-2024. Für noch ältere Targets ein simpler Polyfill:

JavaScript toreversed-polyfill.js
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.

JavaScript string-reverse.js
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'
Output
tpircSavaJ
 😀iH
😀 iH

split('') 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:

JavaScript sparse-reverse.js
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 Position
Output
4
true
false
[ 4, <2 empty items>, 1 ]
true
false

In 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().

JavaScript typed-array.js
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]
Output
[ 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.

JavaScript pipeline.js
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
Output
[ 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?

SituationEmpfehlung
Original soll erhalten bleibenarr.toReversed() (ES2023)
Vor ES2023-Targetsarr.slice().reverse()
In map/filter-Pipelinedirekt .reverse() (Zwischen-Array)
Absteigend sortierenarr.sort((a, b) => b - a)
Array darf mutiert werdenarr.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

/ Weiter

Zurück zu Arrays

Zur Übersicht