How to Add an Element to the Beginning of an Array in JavaScript: An Under-the-Hood Analysis

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why This Question Has Thousands of Views on Stack Overflow

\n\n

Anyone who has ever written JavaScript has worked with arrays. They are everywhere: product lists, task queues, user action history. And sooner or later, the question arises: "How do I add an element to the beginning of an array in JavaScript?" On Stack Overflow, this question has garnered hundreds of thousands of views and dozens of answers. Why? Because behind the apparent simplicity lies a whole layer of knowledge: from performance to the internal workings of the engine.

\n\n

In this article, we won't just show unshift(). We'll look under the hood: how the V8 engine handles insertion at the beginning, why unshift can be slower than push, and what alternatives exist for different scenarios. Let's go!

\n\n

The Basic Way: The unshift() Method

\n\n

The most obvious and common way is to use the built-in unshift() method. It adds one or more elements to the beginning of an array and returns the new length of the array.

\n\n
let fruits = ['banana', 'orange'];\nlet newLength = fruits.unshift('apple');\nconsole.log(fruits); // ['apple', 'banana', 'orange']\nconsole.log(newLength); // 3
\n\n

You can add multiple elements at once:

\n\n
let numbers = [3, 4, 5];\nnumbers.unshift(1, 2);\nconsole.log(numbers); // [1, 2, 3, 4, 5]
\n\n

We could stop here. But let's break down what happens internally when we call unshift().

\n\n

How unshift() Works Under the Hood: A Look at V8

\n\n

An array in JavaScript is not just a contiguous block of memory like in C. In modern engines (V8 in Chrome/Node.js, SpiderMonkey in Firefox), arrays can be implemented in two ways:

\n\n
    \n
  • Fast elements (packed) — a contiguous buffer, C-style. Optimal for reading and writing by index.
  • \n
  • Dictionary elements (sparse) — a hash table. Used when the array becomes "holey" (index gaps) or too large.
  • \n
\n\n

When you call unshift() on a fast array, the engine does the following:

\n\n
    \n
  1. Allocates new memory (or shifts existing memory) by the number of elements being added.
  2. \n
  3. Shifts all existing elements to the right by n positions.
  4. \n
  5. Writes the new elements into the vacated cells at the beginning.
  6. \n
\n\n

Why is unshift Slower than push?

\n\n

The push() method adds an element to the end — it doesn't need to shift anything. unshift(), on the other hand, rewrites the indices for every existing element. If the array has 1000 elements, unshift has to shift all 1000. push simply appends to the end.

\n\n

In V8, there is an optimization: if the array is empty or nearly empty, the shift is almost free. But for large arrays, the performance difference can be tens of times. Especially if you do unshift in a loop.

\n\n
// Bad: O(n²) due to constant shifting\nlet arr = [];\nfor (let i = 0; i < 10000; i++) {\n  arr.unshift(i);\n}\n\n// Good: O(n) — add to the end, then reverse\nlet arr2 = [];\nfor (let i = 0; i < 10000; i++) {\n  arr2.push(i);\n}\narr2.reverse();
\n\n

Alternative: The Spread Operator (ES6+)

\n\n

A modern and elegant way is to use the spread operator ... to create a new array:

\n\n
let oldArray = [2, 3, 4];\nlet newArray = [1, ...oldArray];\nconsole.log(newArray); // [1, 2, 3, 4]
\n\n

This approach does not mutate the original array, which is often convenient in functional programming (React, Redux). But remember: a new array is created, and the old elements are copied. For huge arrays, this can be memory-intensive.

\n\n

Adding Multiple Elements to the Beginning

\n\n
let base =                

Blogs

Book Recommendations