How well do you know JavaScript Arrays?

I decided to write about sparse and dense arrays several months ago. I thought it would be easy and imagined writing a masterpiece based off my multi-year experience with arrays.

Alas, my foray into the intricacies of Arrays unearthed surprising discoveries and shattered my brittle expertise. This series of posts describes my learnings and Aha moments.

Myriad Ways of Making Arrays

Nearly everyone uses [] to create arrays. There are 4 other ways to do make arrays.

1. Making Empty Arrays

let arr1 = []; // array literal
let arr2 = new Array();
let arr3 = Array(); // without the new keyword

Invoking the Array Constructor without the new prefix is not recommended.

2. Making Empty Arrays with a Specific Length

// Creating an empty array of length 2
let arr3 = [,,]; // Last comma is ignored
let arr4 = new Array(2); // has 2 holes!

3. Array with Elements

// Creating an array with elements
let arr5 = [1, 2, 3];
let arr6 = new Array(1,2,3);

4. Using the ES2015 Array.Of Static Method

// Creating an array with elements
let a = Array.of(1,2,3); // [1,2,3]
let b = Array.of(1); // [1]

Note that Array.of(7) creates an array with a single element 7 while new Array(7) creates an Array with 7 empty slots.

The Confusing Array Constructor

The variadic nature of the Array Constructor is confusing. If invoked with a single argument, that value is interpreted as the length of the array to create. However, there are more arguments, they get interpreted as elements of the array!

The Array Constructor explained

  1. If invoked with a single argument:
    1. If the argument is a number, then the value must be a Natural Number less than 232-1; i.e. the integer interval [0..232-1]. Otherwise, it throws an error.
    2. If the argument is non-numeric (e.g. null), it becomes the only element in the array.
  2. If invoked with multiple arguments; these values become the array elements.

Let’s look at the code!

// Rule 1.1
new Array(2); // [empty x 2]
new Array(-1); // error

// Rule 1.2
new Array('2'); // ['2']

// Rule 2
new Array(-100, '1'); // [-100, '1']

How would you create an array with just one number using the Array constructor?

How big can Arrays get?

The maximum length of an array in JavaScript is 4294967295 (232 – 1). Let’s see what happens if we exceed that value.

let maxLen = 2**32 - 1;
new Array(maxLen + 1);
// Uncaught RangeError: Invalid array length

let bigArray = new Array(maxLen);
bigArray.length = maxLen + 1;
// Uncaught RangeError: Invalid array length

Let’s see a way to bypass this limit by leveraging our knowledge that arrays are objects under the covers.

let maxLen = 2**32 - 1;
let bigArray = new Array(maxLen);

bigArray[maxLen+1] = 1;
console.log(bigArray[maxLen+1]); // 1
// (4294967295) [empty × 4294967295, 4294967296:1]

// RangeError:Invalid array length

// (4294967295) 
// [empty × 4294967295, 4294967296:1, 4294967295:2]

Two eye-opening discoveries:

  1. push throws an error but still sets the property value.
  2. Running console.table(bigArray) crashes FireFox. Try it.

The Array Length property

JavaScript array indices start from zero; thus the length is always 1 more than the last array element index.

let arr = [];
console.log(arr.length); // 0
arr[4] = 4;
console.log(arr.length); // 5

Length is Settable

The following code snippet increases the array size to 5.

let arr = [];
arr.length = 5;

// (4) [empty x 5]

This trick can be used to trim arrays by reducing length.

let arr = [1,2,3,4,5,6,7,8,9,10];
arr.length = 3;
// [1,2,3]

Emptying Arrays

You can set length to 0 or reassign the reference to a new array.

let arr = [1,2,3];
arr.length = 0;
arr = []; // faster

The similitude is being asked to empty a sack filled with clothes.

  1. You can take out each individual cloth piece one at a time (set length to zero).
  2. You can replace the sack with a brand new empty sack (re-assigning to []). The old sack and its contents still exist somewhere (see closures).

Just like in the real life example, it is faster to do assign an empty array. Setting the length to zero clears the array by deleting each array element and is thus understandably slower.

Clearing all references

let a = Array.of(1,2,3);
let b = a;

b.length = 0;
console.log(a); // []

This approach can be a double-edged sword since it clears all references but it comes handy for scenarios when arrays are declared with const.

Clearing only the reference

let a = Array.of(1,2,3);
let b = a;

b = []
console.log(a); // [1,2,3]

Do you know arrays are objects under the covers? The next post dives into these subtleties and promises more fun.




Leave a Reply

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

You are commenting using your 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.