Array.prototype.push() hängt ein oder mehrere Werte in-place ans Ende eines Arrays an und liefert die neue Länge zurück — nicht das Array. Das ist die häufigste Quelle von Anfänger-Bugs: const x = arr.push(5) setzt x auf eine Zahl, nicht auf das Array. Die Methode mutiert das Original — wer immutable arbeiten will (Redux, React-State), nutzt stattdessen [...arr, neu] oder arr.concat(neu). Dieser Artikel zeigt die Grundform, das Verhalten bei Multi-Argument, das alte push.apply-Pattern zum Flach-Anhängen und die typischen Fallen.

Signatur & Grundform

JavaScript signatur.js
arr.push(...werte: T[]): number   // neue Länge nach push
JavaScript grundform.js
const arr = [1, 2, 3];
const neueLaenge = arr.push(4);

console.log(arr);            // [1, 2, 3, 4]
console.log(neueLaenge);     // 4 — die LÄNGE, nicht das Array!
Output
[ 1, 2, 3, 4 ]
4

Dass push die Länge zurückgibt und nicht das Array, ist ein häufiger Stolperer. Code wie const next = list.push(item) liefert eine Zahl.

Mehrere Werte gleichzeitig

push akzeptiert beliebig viele Argumente — alle werden in der übergebenen Reihenfolge angehängt.

JavaScript multi.js
const buchstaben = ['a', 'b'];
buchstaben.push('c', 'd', 'e');
console.log(buchstaben);     // ['a', 'b', 'c', 'd', 'e']

// Mit Spread aus einem anderen Array
const start = [1, 2];
const rest = [3, 4, 5];
start.push(...rest);
console.log(start);          // [1, 2, 3, 4, 5]
Output
[ 'a', 'b', 'c', 'd', 'e' ]
[ 1, 2, 3, 4, 5 ]

Wer ein Array als Einzel-Element anhängen will, übergibt es ohne Spread:

JavaScript array-als-element.js
const a = [1, 2];
a.push([3, 4]);
console.log(a);              // [1, 2, [3, 4]] — Array als verschachteltes Element
Output
[ 1, 2, [ 3, 4 ] ]

Immutable-Alternative: Spread

In React/Redux und allgemein bei State-Management ist Mutation tabu — push ist dann das falsche Werkzeug. Spread baut ein neues Array:

JavaScript immutable.js
const original = [1, 2, 3];

// Mutation
original.push(4);
console.log(original);       // [1, 2, 3, 4]

// Immutable mit Spread
const erweitert = [...original, 5];
console.log(original);       // [1, 2, 3, 4] — unverändert
console.log(erweitert);      // [1, 2, 3, 4, 5]

// Mehrere Werte
const noch = [...original, 5, 6, 7];
console.log(noch);           // [1, 2, 3, 4, 5, 6, 7]
Output
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5, 6, 7 ]

push.apply — Flach-Anhängen vor Spread

Pre-ES2015 war push.apply(arr, otherArr) das Standard-Pattern, um ein Array flach an ein anderes anzuhängen — ohne dass das angehängte Array als verschachteltes Element landet.

JavaScript push-apply.js
const ziel = [1, 2];
const quelle = [3, 4, 5];

// Alt: push.apply
Array.prototype.push.apply(ziel, quelle);
console.log(ziel);           // [1, 2, 3, 4, 5]

// Modern: spread
const ziel2 = [1, 2];
ziel2.push(...quelle);
console.log(ziel2);          // [1, 2, 3, 4, 5]
Output
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5 ]

In modernem Code: immer Spread. push.apply taucht aber in Legacy-Code reichlich auf.

push in Schleifen — Build-Pattern

Eine der häufigsten Anwendungen: in einer Schleife ein Ergebnis-Array aufbauen.

JavaScript schleifen.js
const quadrate = [];
for (let i = 1; i <= 5; i++) {
    quadrate.push(i * i);
}
console.log(quadrate);       // [1, 4, 9, 16, 25]

// Funktional-Stil-Alternative
const quadrate2 = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(quadrate2);
Output
[ 1, 4, 9, 16, 25 ]
[ 1, 4, 9, 16, 25 ]

Beide Formen sind idiomatisch. Die Schleife mit push ist einfacher bei dynamischen Bedingungen (Filter oder mehrere Pushes pro Iteration), die funktionale Form ist kürzer bei reinen Mappings.

push + shift als Queue

Eine FIFO-Queue lässt sich mit push (Anhängen am Ende) und shift (Entfernen am Anfang) bauen.

JavaScript queue.js
const queue = [];
queue.push('A');
queue.push('B');
queue.push('C');

while (queue.length > 0) {
    const next = queue.shift();
    console.log('Verarbeite:', next);
}
Output
Verarbeite: A
Verarbeite: B
Verarbeite: C

Achtung: shift ist O(n) — alle anderen Elemente werden nach vorn geschoben. Bei großen Queues lieber Deque-Pattern oder ein Library-Datentyp.

push modifiziert length direkt

Was passiert intern: push schreibt das neue Element an Index arr.length und inkrementiert length um die Anzahl der Argumente.

JavaScript length-manuell.js
const arr = [1, 2, 3];

// push macht intern das:
// arr[arr.length] = 4;  arr.length++;

// Manuell — identische Wirkung
arr[arr.length] = 4;
console.log(arr);            // [1, 2, 3, 4]

// length manuell hochsetzen erzeugt sparse Slots
arr.length = 7;
console.log(arr);            // [1, 2, 3, 4, <3 empty items>]
console.log(4 in arr);       // false — Loch

// length runtersetzen schneidet ab
arr.length = 2;
console.log(arr);            // [1, 2]
Output
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4, <3 empty items> ]
false
[ 1, 2 ]

push selbst erzeugt nie Löcher — es schreibt jedes übergebene Argument als echtes Element.

Performance — meistens optimal

push ist eine der schnellsten Array-Operationen. Engines amortisieren die Erweiterung des internen Backing-Storage (Verdoppelungs-Strategie), Push ist im Schnitt O(1).

Bei sehr großen Push-Mengen ist eine einmalige Allokation oft schneller:

JavaScript bulk.js
// Bulk-Push mit Spread — eine Argument-Liste, ein Allocate
const ziel = [];
const quelle = Array.from({ length: 1000 }, (_, i) => i);
ziel.push(...quelle);
console.log(ziel.length);    // 1000

// Bei MILLIONEN Elementen: Spread läuft in das Argument-Stack-Limit
// Workaround: in Chunks pushen
const sehrGross = Array.from({ length: 100000 }, (_, i) => i);
const chunk = 1000;
const ziel2 = [];
for (let i = 0; i < sehrGross.length; i += chunk) {
    ziel2.push(...sehrGross.slice(i, i + chunk));
}
console.log(ziel2.length);
Output
1000
100000

Häufige Stolperfallen

push gibt die neue LÄNGE zurück, nicht das Array

const x = arr.push(5) setzt x auf die neue Länge (Number), nicht auf arr. Anfänger erwarten oft das modifizierte Array zurück. Wer Chaining will: separate Statements oder Spread-Pattern.

push mutiert — in React/Redux nie direkt

setItems(items.push(neu)) ist ein React-Anti-Pattern: push mutiert items und gibt eine Zahl zurück. React sieht keinen State-Wechsel UND State ist intern mutiert. Korrekt: setItems([...items, neu]).

push.apply ersetzt durch push(...arr) mit Spread

Array.prototype.push.apply(ziel, quelle) ist Pre-ES2015-Pattern für „alle Elemente flach anhängen". Modern: ziel.push(...quelle). Achtung Stack-Limit bei sehr großen Arrays.

push(arr) hängt das Array als verschachteltes Element an

a.push([3, 4]) ergibt [..., [3, 4]] — nicht [..., 3, 4]. Wer flat anhängen will: a.push(...[3, 4]) mit Spread, oder a.concat([3, 4]) für immutable.

push erzeugt nie sparse Slots — undefined wird zu echtem Element

arr.push(undefined) hängt undefined als echten Wert an, kein Loch. in-Operator zeigt es: arr.length - 1 in arr ist true. Anders als arr.length = arr.length + 1, das ein Loch erzeugt.

push amortisiert O(1) — bei vorhersehbarer Größe lohnt sich vorallokieren

Engines verdoppeln den internen Speicher beim Wachsen. Bei sehr großen Push-Sequenzen mit bekannter Größe kann arr.length = n vor dem Befüllen die Reallocate-Schritte sparen. In normalem Code irrelevant.

push(...) mit MILLIONEN Argumenten → RangeError

arr.push(...riesigesArray) übergibt jedes Element als eigenes Argument an die Funktion. V8/SpiderMonkey haben einen Argument-Stack-Limit (~65k). Bei größeren Daten: in Chunks pushen oder concat bzw. einfaches for mit einzelnen pushes.

push auf Array-Like funktioniert auch — wenn length änderbar

Array.prototype.push.call(arrayLike, 1, 2) funktioniert, sofern das Array-Like eine writable length-Property hat. Praktisch selten gebraucht; bei arguments z.B. funktioniert es. Bei DOM-NodeLists nicht (length ist readonly).

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Arrays

Zur Übersicht