Holey JavaScript Arrays


Take a look at the code sample below.

let array = [,,undefined,1,2,,];
console.log(array);
Chrome Version 83.0.4103.116

Interesting! What is empty and why is it different from undefined? This article dives into this issue (called Elision in JavaScript) and offers yet another delightful deep dive into the weird warts of JavaScript.

Elision: omission of a passage in a book, speech, or film.

https://www.google.com/search?q=Elision+definition

Sparse Arrays

An array is sparse if its length is greater the number of elements it contains. Thus, it is an array containing holes; holes are empty slots which contain nothing. This nothingness is represented as undefined however it is different from the JavaScript undefined value. Confusing eh, read why you should not use isNaN in JavaScript.

This is one of the weird parts of JavaScript; since there is no real empty value, JavaScript returns undefined instead. Holes in the array means there are no elements at those unassigned indexes. Remember that arrays are objects and objects do not need to have contiguous elements.

In JavaScript, undefined is the default value for variables that have been declared but not assigned any value.

Making Sparse Arrays

1. Using the Array Constructor

The simplest way is to use the Array Constructor with a count.

let sparseArray = new Array(10);
console.log(sparseArray);
// (10) [empty × 10]

2. Assigning a value to an index after length

let a = [];
a[6] = 0; // assign value to index after length
console.log(a);
// [empty x 5, 0]

3. Changing the length property

let b = [];
b.length = 5; // change length property
console.log(b);
// [empty x 5]

4. Deleting elements from an array

Note: deleting array elements does not alter the array length. Rather it puts holes in those locations. Again, holes are not same as undefined, they are empty slots.

let c = [1,2,3,4];
delete c[0], delete c[1], delete c[2]; // delete
console.log(c);
// [empty x 3, 4]

You can read more about the comma operator here.

2. Using the Array literal

let d = [,,,,]; // empty slots
console.log(d);
// [empty x 4], last comma doesn't count

Undefined vs Empty?

let weird = new Array(2);
weird[0] = undefined;
console.log(weird);
// [undefined, empty]

console.log(weird[0]); // undefined
console.log(weird[1]); // undefined

weird[0] === weird[1]; // true
weird[0] === undefined; // true

How do you know if an array slot is empty or undefined? Obviously comparing to undefined does not work. This is where the in operator is useful.

Seeing empty slots: The in Operator

The in operator is an object operator that checks if a property exists in an object or its prototype chain. Since arrays are objects, this is a foolproof way to identify holes. Empty slots have no defined index values at their locations because the property does not exist.

let sparseArray = new Array(10);
sparseArray.length
// 10

0 in sparseArray
// false

9 in sparseArray
// false

sparseArray[0] = undefined;
0 in sparseArray
// true

This shows that the 0th slot is now filled with undefined and not empty.

Why do arrays need to be sparse?

Performance. A huge sparse array e.g. new Array(9999999) contains nothing until elements are inserted.

The V8 engine optimizes for performance by distinguishing between dense and sparse arrays. See this great article on HOLEY and PACKED element kinds: https://v8.dev/blog/elements-kinds.

Large Sparse Array

let size = 500000000;
console.time();
let timed = new Array(size);
console.timeEnd();
// ~ 0.03 ms

Large Dense Array

Warning: this snippet will crash your browser.

let size = 500000000;
console.time();
let timed = new Array(size);
console.timeEnd();

Summary

JavaScript Arrays are closer to ArrayLists in C#/Java since sizes can grow organically. Arrays grow/shrink at will and can store any valid JavaScript value type.

  1. Sparse arrays contain holes
  2. Dense arrays contain contiguous elements (even if they are undefined).

The ECMAScript standard leaves implementation up to browser vendors to choose how to optimize.

Avoid holey arrays because JavaScript methods handle them inconsistently (i.e., some methods ignore them, others don’t). The next post in this series should provide examples of this.

Liked this post? Follow me on Twitter to get notified when new posts go out.

Leave a Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.