JavaScript Arrays: Empty Slots
Welcome to the Empty Slots lesson!
JavaScript arrays have a concept of "slots" that can be very confusing.
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
When we use
new Array, the array appears to be full ofundefineds.>
new Array(1)[0];Result:
undefined
However, index 0 of that array doesn't contain
undefined. Instead, it's an "empty slot". Empty means that there's nothing in the slot, not even anundefined. But JavaScript has to give us some value, so it gives usundefined.For arrays,
x in aasks whether the array has something in index x. For example, the array['a', 'b', 'c']has elements in indexes 0 through 2.>
const numbers = ['a', 'b', 'c'];1 in numbers;Result:
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
3 in numbers;Result:
false
We can use the
inoperator to see the difference between an array containingundefinedand an array with an empty slot. First, here's an array containingundefined:>
const array = new Array(1).fill(undefined);array[0];Result:
undefined
>
0 in new Array(1).fill(undefined);Result:
true
Now here's an array with an empty slot. We still get
undefinedwhen we look inside of the array, but the index 0 is not in the array!>
const array = new Array(1);array[0];Result:
undefined
>
0 in new Array(1);Result:
false
Adding elements past the end of an array causes the array to grow.
>
const array = [];array[2] = 1;array.length;Result:
3
We never put a value in indexes 0 or 1, so those slots are empty. Accessing them gives us
undefined.>
const array = [];array[2] = 1;array[0];Result:
undefined
Like before, we can use the
inoperator to see that some slots are empty.>
const array = [];array[2] = 1;2 in array;Result:
true
>
const array = [];array[2] = 1;1 in array;Result:
false
We can
.fillin those empty slots. That's why.fillis so often paired withnew Array(). This is a good way to avoid arrays with empty slots.>
const allEmpty = new Array(3);allEmpty.fill('d');Result:
['d', 'd', 'd']
Empty slots may seem like a curiosity, but they can lead to confusing bugs. For example, the
.forEachmethod skips over empty slots when looping. It doesn't even call our callback function for those slots!>
const array = new Array(3);let elementsCounted = 0;array.forEach(x => {elementsCounted += 1;});elementsCounted;Result:
0
>
const array = new Array(3);array[1] = true;let elementsCounted = 0;array.forEach(x => {elementsCounted += 1;});elementsCounted;Result:
1
.mapalso behaves strangely with empty slots. It calls our callback function for each non-empty slot, as usual. But like.forEach, it doesn't even call our callback for empty slots. They're still empty in the final array, even though it seems like.mapshould've replaced them.>
const allEmpty = new Array(2);const stillEmpty = allEmpty.map(x => true);[stillEmpty[0], stillEmpty[1]];Result:
>
const allEmpty = new Array(2);const stillEmpty = allEmpty.map(x => true);0 in stillEmpty;Result:
false
.reduce,.filter, and some other methods also skip empty slots. Here are our tips to avoid arrays with empty slots:- Always use
.fillafter callingnew Array(someSize). - Don't write to indexes past the end of an array.
- Always use
Finally, a note on terminology. An array with empty slots is sometimes called a "sparse" array. "Sparse" means "thinly dispersed or scattered", which is appropriate for an array where only some of the elements actually exist!