Packed and Holey Arrays : What You Need to Know
Reveal the Lesser-Known Aspects of JS Arrays in the V8 engine
Up until now, most of us understand that arrays are contiguous blocks of memory used to store related data. We're familiar with prototype methods and properties in JavaScript that we've used, such as .forEach(), .map(), .fill(), or .filter(), along with accessing properties like length. While there's much more to arrays beyond these basics, one interesting aspect often overlooked is that arrays come in different types. Surprised? Let’s explore the different types of arrays in this article.
Recently, I came across a Youtube video stating “You don’t know array in javascript“ after, I just finished learning Javascript from this same guy who made this video feeling intrigued, clicked on it and little did I know that it is going to blow my mind away with this beautiful insight knowledge of arrays about how it is optimised and implemented for each different type of array you create . Yes, arrays also have an internal distinction based on the type of elements.
Types of Arrays
Arrays are internally categorized into two broad types:
PACKED arrays
HOLEY arrays
PACKED arrays are those where every position is filled and has its elements defined, with no empty spaces. In contrast, HOLEY arrays have some empty spaces or “holes“ in them, where elements are missing or undefined at some indices.
These packed and holey arrays also belong to different underlying categories according to the type of elements stored in them such as,
SMI(Small Integer Element)-Arrays with elements that are small integers (typically 31-bit or 32-bit signed integers).
Double Elements-Arrays containing double-precision (64-bit) floating-point numbers.
Object Elements-Arrays containing non-primitive types like objects, strings, or mixed types.
Packed arrays are categorized based on their elements. A Packed_SMI array contains only small integers, such as [1, 2, 3, 4] If a different type of value, such as a floating-point number (1.0) or a string (“hey”), is introduced (e.g., [1, 2, 3, 4, “hey“]), the array transitions to a Packed_Object array. Similarly, a Packed_Double array consists entirely of floating-point numbers, such as [1.0, 2.0, 3.0, 4.0].
In similar ways holey arrays are also categorised into Holey_SMI, Holey_Object and Holey_Double but in here “holes” or empty positions are allowed.
Optimization and Access Efficiency
Now, here’s where it gets interesting. Packed arrays are much more efficient than holey arrays. This is because maintaining a uniform and contiguous structure in the array helps JavaScript optimize performance when accessing the data.
So why are packed arrays more optimized? Let’s break it down by looking at the process of accessing elements in the array.
So, the process is as follows :
Bound check- This checks whether the element being accessed is within the array bounds. For example, if you try to access an index that doesn’t exist (e.g., the 10th index in an array with only 4 elements), it will return undefined.
.hasOwnProperty()- This internal check verifies whether the property (index) exists directly on the array. If not, it moves on to check its prototype chain.
Prototype Checks- If the element isn't found, V8 will look through the array's prototype chain, which includes the array prototype and the Object.prototype. If the index is missing at all levels, undefined is returned.
Note
In packed arrays, every index within the bounds is guaranteed to have a defined element. Once the bounds check passes, the element retrieval is direct and efficient.
In contrast, holey arrays may contain gaps (holes) even within valid bounds. Passing the bounds check doesn’t guarantee a valid element at the index—it might be an empty hole.Even after passing the bounds check, the engine must handle the possibility of a missing element, adding extra overhead.
The overhead caused by holey arrays constitute of the .hasOwnProperty()(or equivalent operations) being run again and again to find the element ,this is a very expensive method as it verifies an element's explicit existence and traverses the object’s prototype chain. Frequent execution of such checks makes holey arrays inefficient for both storage and access.
Also,The memory for holey arrays is less compact because the gaps between elements lead to fragmentation, making it harder for the JavaScript engine to optimize the memory layout.
The Holey arrays are mostly used when elements are dynamically added or removed in contrast Packed arrays are used for storing a list of objects that don't change frequently.
Optimization Rankings
When it comes to optimization, here’s how the array types rank:
Packed_SMI » Packed_Double » Packed_Object » Holey_SMI » Holey_Object » Holey_Double
And Once an array's internal categorization degrades, it cannot be upgraded to a more optimized array type by using any method.
Conclusion
And That’s a wrap :), I tried to summarize whatever I learned from it, into this small article .Hope,you like it !!
If you're curious, you can tweak around and use V8-debug to read all about the internal structure of your array (not covered in this article). You can see how to do that using the embedded video link.
If any suggestions, please drop them in the comments will highly appreciate it.
Here’s the video that inspired this article:
Thank you, Hitesh Choudhary sir for introducing this beautiful aspect of Array to me .
:)