We generally work with the former type, but the latter one exists too. Let's understand the difference between the two, and specifically, how to handle the latter one.
Array.prototype and behave like a typical ordered list-like data structure.
Beginners often confuse an array as a primitive data type. If you want to create a primitive one, go for a typed array.
Here's how we use a dense array. That's the most common use case in our day-to-day programming. There's no hole between the elements.
// A dense array const a = [ 1, 2, 3, 4, 5 ]; console.log(a); // => [ 1, 2, 3, 4, 5 ] console.log(a.length); // => 5
And, here's a sparse array! Note, the third element has a hole. There's nothing in that location.
// A sparse array const a = [ 1, 2, , 3, 4, 5 ]; console.log(a); // => [ 1, 2, <empty slot>, 3, 4, 5 ] console.log(a.length); // => 6
Pay attention to the length property of a sparse array. It's six, though only five elements exist. Furthermore, these filled elements are allocated non-contiguous memory locations.
A sparse array can be declared in different ways. Let's take a look!
// Different ways a sparse array can be created let a = new Array(10); let b = ; b = 'Hello World!'; const c = [ 1, 2, 3, 4, 5 ]; delete c; // Deleting second element creates a hole (sparse array) console.log(a); // => [ <10 empty slots> ] length: 10 console.log(b, b, b.length); // => [ <10 empty slots>, ... ] undefined 26
The last line in the code snippet shown above is worth noticing. You can see that trying to access a hole
undefined which is confusing.
Accessing a non-existing array index (hole) returns
undefined assigned to an existing variable. We can confirm the non-existing index through the
// Display available array keys (index values) const a = [ 1, 2, , 3, 4, 5 ]; console.log(Object.keys(a)); // => [ "0", "1", "3", "4", "5" ]
So, if accessing a sparse array hole and an element with an undefined value gives the same
undefined result, how do we distinguish a hole from a valid element reference?
Here's a simple check for the same.
// Check for a hole in a sparse array const sparseArray = [ undefined, , ]; console.log(sparseArray.hasOwnProperty(0)) // => true console.log(sparseArray.hasOwnProperty(1)); // => false
And, what about copying a sparse array?
You can try it in 3 different ways. An assignment operator, use of a spread
[ ...Object ] operator, or use of
Which one is the correct way to make a copy (not a reference) of a sparse array? Let's see!
// Making a copy of a sparse array let source = [ undefined, , ]; let badCopy = source; // => it's a reference and not a copy let anotherBadCopy = [ ...source ]; let goodCopy = source.slice(); console.log(source); // => [ undefined, <1 empty slot> ] console.log(anotherbadCopy); // => [ undefined, undefined ] console.log(goodCopy) // => [ undefined, <1 empty slot> ]
So, you can see, it's the
slice() method that gives the correct result. The spread operator replaces the hole with an element having an
undefined value. That's not what we want.
I've never used sparse arrays while coding real-world projects. Whenever there is a need to use one, I'll suggest using either a
Map or a
Set data structure.