Einleitung: Warum diese Frage tausende Aufrufe auf Stack Overflow gesammelt hat
\n\nJeder, der jemals in JavaScript programmiert hat, ist auf Arrays gestoßen. Sie sind überall: Produktlisten, Aufgabenwarteschlangen, Benutzeraktionsverläufe. Und früher oder später stellt sich die Frage: „Wie füge ich ein Element am Anfang eines Arrays in JavaScript hinzu?“ Auf Stack Overflow hat diese Frage Hunderttausende von Aufrufen und Dutzende von Antworten erhalten. Warum? Weil sich hinter der scheinbaren Einfachheit eine ganze Schicht von Wissen verbirgt: von der Leistung bis zur internen Funktionsweise der Engine.
\n\nIn diesem Artikel zeigen wir nicht nur unshift(). Wir werfen einen Blick „unter die Haube“: wie die V8-Engine das Einfügen am Anfang verarbeitet, warum unshift langsamer sein kann als push und welche Alternativen für verschiedene Szenarien existieren. Los geht's!
Die grundlegende Methode: unshift()
\n\nDer offensichtlichste und gebräuchlichste Weg ist die Verwendung der integrierten Methode unshift(). Sie fügt ein oder mehrere Elemente am Anfang eines Arrays hinzu und gibt die neue Länge des Arrays zurück.
let fruits = ['banana', 'orange'];\nlet newLength = fruits.unshift('apple');\nconsole.log(fruits); // ['apple', 'banana', 'orange']\nconsole.log(newLength); // 3\n\nSie können auch mehrere Elemente auf einmal hinzufügen:
\n\nlet numbers = [3, 4, 5];\nnumbers.unshift(1, 2);\nconsole.log(numbers); // [1, 2, 3, 4, 5]\n\nDamit könnte man es bewenden lassen. Aber lassen Sie uns untersuchen, was intern passiert, wenn wir unshift() aufrufen.
Wie funktioniert unshift() unter der Haube: Ein Blick auf V8
\n\nEin Array in JavaScript ist nicht einfach ein zusammenhängender Speicherblock wie in C. In modernen Engines (V8 in Chrome/Node.js, SpiderMonkey in Firefox) können Arrays auf zwei Arten implementiert sein:
\n\n- \n
- Fast elements (gepackt) — ein zusammenhängender Puffer im C-Stil. Optimal zum Lesen und Schreiben per Index. \n
- Dictionary elements (spärlich) — eine Hash-Tabelle. Wird verwendet, wenn das Array „löchrig“ wird (Indexlücken) oder zu groß wird. \n
Wenn Sie unshift() auf einem Fast-Array aufrufen, macht die Engine Folgendes:
- \n
- Sie reserviert neuen Speicher (oder verschiebt vorhandenen) um die Anzahl der hinzuzufügenden Elemente. \n
- Sie verschiebt alle vorhandenen Elemente um
nPositionen nach rechts. \n - Sie schreibt die neuen Elemente in die freigewordenen Zellen am Anfang. \n
Warum ist unshift langsamer als push?
\n\nDie Methode push() fügt ein Element am Ende hinzu – sie muss nichts verschieben. unshift() hingegen überschreibt die Indizes für jedes vorhandene Element. Wenn das Array 1000 Elemente hat, muss unshift alle 1000 verschieben. push hängt einfach am Ende an.
In V8 gibt es eine Optimierung: Wenn das Array leer oder fast leer ist, ist das Verschieben nahezu kostenlos. Aber bei großen Arrays kann der Leistungsunterschied um ein Vielfaches betragen. Besonders, wenn unshift in einer Schleife verwendet wird.
// Schlecht: O(n²) aufgrund ständigen Verschiebens\nlet arr = [];\nfor (let i = 0; i < 10000; i++) {\n arr.unshift(i);\n}\n\n// Gut: O(n) — am Ende hinzufügen, dann umkehren\nlet arr2 = [];\nfor (let i = 0; i < 10000; i++) {\n arr2.push(i);\n}\narr2.reverse();\n\nAlternative: Der Spread-Operator (ES6+)
\n\nEine moderne und elegante Methode ist die Verwendung des Spread-Operators ... zum Erstellen eines neuen Arrays:
let oldArray = [2, 3, 4];\nlet newArray = [1, ...oldArray];\nconsole.log(newArray); // [1, 2, 3, 4]\n\nDieser Ansatz mutiert das ursprüngliche Array nicht, was in der funktionalen Programmierung (React, Redux) oft praktisch ist. Aber denken Sie daran: Es wird ein neues Array erstellt und die alten Elemente werden kopiert. Bei riesigen Arrays kann dies speicherintensiv sein.
\n\nHinzufügen mehrerer Elemente am Anfang
\n\nlet base =