Don't Fear Sparse Arrays in JavaScript

By Rob Gravelle

With Halloween just around the corner, I've decided to tackle a particularly frightening topic: JavaScript arrays. You see, JavaScript arrays are not quite like those of more restrictive languages such as Java, in that they are sparse arrays. That means that they can contain gaps between elements, gaps where the unwary can fall through or be swallowed up by bugs! Scared yet? After you read about all the ways that sparse arrays can affect your code, you will be! All joking aside, sparse arrays do require some special handling, which is the topic of today's article.

What Exactly Are Arrays in JavaScript?

JavaScript Arrays are first class objects. As such, they have their own constructors, methods, and properties. They also share many qualities of their counterparts in other languages, such as Java or C++, such as being zero based. However, their support for dynamic arrays that can grow as needed more closely resembles the Java ArrayList class than regular vanilla arrays. Moreover, elements can be added at any index in an array so that gaps may result, creating the aforementioned sparse array.

var a = [];
a[2] = 'A';
'); //outputs ",,A" a[10] = 'B'; document.write(a); //outputs ",,A,,,,,,,,B"

The above code shows us that more elements are automatically allocated to the array to accommodate the new element at the prescribed index: first up to the second index, then to the tenth. Hence, the length property of the array would show that the a array contains 11 elements, the highest index plus one. Two elements contain values, while the other nine contain the undefined constant. To include these in the array output, we can loop through the array ourselves using a for loop:

Array.prototype.toString = function() {
  var outstring = '';
  for(var i=0;i

Guess the Length Game

And now it's time to put the previous section's material to the test and play the Guess the Length Game. That's where I create an array and you guess what its length property might be.

The first code snippet creates an Array using the new Array(length) constructor:

var arr = new Array(10);
arr[4] = 'test';
arr[10] = 'test2';

Yes, that's right; it's eleven. The assignment to the tenth element added one to the length because the array is zero-based.

The next example uses the new Array(elt1, elt2, ...eltN) constructor to assign elements immediately upon creation:

var arr2 = new Array(1,2,4,6,7,8,10);
arr2[99] = 'the new guy';

The length started at 7 to accommodate the seven elements that we populated via the constructor. However, that last assignment caused the array to grow to the size of ninety-nine plus one, making it one hundred.

Our last brain teaser instantiates an empty array using square brackets ([]), which are used to represent an array literal. Next, the twenty fourth element slot is explicitly set to the undefined constant:

var arr3 = [];
arr3[24] = undefined;

The initial empty array had a length of zero, but again, assigning a value to any index of zero or above increases the size to that index plus one - even if the assigned value is undefined!

No More Out of Bounds Exceptions

The Array.length property is useful to iterate over arrays using a for loop, but you can select any range you wish. In fact, there is nothing preventing you from venturing outside of an array's bounds. You'll just get a value of undefined:

var a = [];
for (var i=0; i

Therefore, never use the undefined value to determine the lower or upper bounds of an array. Use the length property in a for loop, or, you can use a for in loop. That's next.

Heed This Warning Regarding Negative Indices

While JavaScript arrays are officially zero based, they can accept negative indices. But be forewarned, to use negative indices essentially cuts you off from using many existing native Array methods. All Array methods use the zero position as the lower bounds, so any elements below that will be ignored! The length property will also count from zero so that values residing at negative indices will not be counted. Having said that, you can override existing methods or use your own if you really want to go down that route, but that may introduce bugs into your code and require a substantial amount of extra coding.

The fact that you require negative indices is often a sign that you don't want a traditional array at all, but rather an associative array, better know as a Hash Table or Hash. It just so happens that all objects in JavaScript are associative arrays. Behind the familiar object notation using the dot (i.e., obj.prop) JavaScript is actually accessing the property using association as in obj['prop']. Since JavaScript arrays are objects themselves, they also possess such properties so that a[1] and a['1'] actually refer to the same object. How is this possible? In fact, Array indices are converted to strings behind the scenes so that each element is referenced by the numeric property name. This can be verified by iterating through the Array using a for in loop, which is meant for looping over an object's properties (and methods):

var a = [];
a[2] = 'A';
a[10] = 'B';
a[-5] = 'c';
a['6'] = 'prop';

for(var i in a){ 
  document.write(+ i + ': ' + a[i] + ' (' + (typeof i) + ')  ');
//outputs "2: A (string)   6: prop (string)   10: B (string)   -5: c (string)"  

Likewise, adding a property using dot notation will produce similar output:

a.prop = 'a property';

//outputs "2: A (string)   10: B (string)   -5: c (string)   prop: a property (string)"


Alright, maybe that wasn't so scary. Knowing how sparse arrays work does alleviate a lot of the uncertainty of working with them. But fear not - I mean do fear - there's plenty more terrifying subject matter where JS is concerned. The next article will curdle your blood, I assure you!

Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
Thanks for your registration, follow us on our social networks to keep up-to-date