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
arr.push(...werte: T[]): number // neue Länge nach pushconst 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![ 1, 2, 3, 4 ]
4Dass 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.
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][ 'a', 'b', 'c', 'd', 'e' ]
[ 1, 2, 3, 4, 5 ]Wer ein Array als Einzel-Element anhängen will, übergibt es ohne Spread:
const a = [1, 2];
a.push([3, 4]);
console.log(a); // [1, 2, [3, 4]] — Array als verschachteltes Element[ 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:
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][ 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.
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][ 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.
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);[ 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.
const queue = [];
queue.push('A');
queue.push('B');
queue.push('C');
while (queue.length > 0) {
const next = queue.shift();
console.log('Verarbeite:', next);
}Verarbeite: A
Verarbeite: B
Verarbeite: CAchtung: 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.
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][ 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:
// 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);1000
100000Hä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).