JavaScript Arrays Are Objects


Arrays are Objects

You can define new properties on arrays just like objects.

let arr = [1,2,3];
arr.colour = "blue"

console.log(arr); 
// [1, 2, 3, colour: "blue"]

arr['size'] = 10000;
console.log(arr);
// [1, 2, 3, colour: "blue", size: 10000]

console.log(arr.length);
// 3

Note that the array length property is unchanged by setting these properties.

Simulating Arrays with Objects

Let’s take the counterexample, can we get an object to simulate array-like behaviours? While this is possible with some JavaScript-fu, this post will not go into such details.

This is a very bare-bones example of what an array-like object might look like:

let arr = [1, 2, 3];
let obj = { 0 : 1, 1 : 2, 2 : 3, length: 3};

Note: The object length property will not increase on setting new numeric fields. Read about property descriptors to learn how to simulate this.

How about adding numeric object keys?

Using numeric keys as object properties requires enclosing in quotes.

let obj = {};
obj['4'] = 4;

console.log(obj); // {4: 4}
console.log(obj['4'); // 4

Does this apply to arrays as well?

let arr = [];
arr['4'] = 4;

console.log(arr); // [empty x 4, 4]
console.log(arr['4']); // 4
console.log(arr[4]); // 4

It works?! Yes, it does!! Remember, Arrays are objects under the covers. Let’s dive into the details to understand why Arrays accept string indices.

Let’s talk about Array Indices

This time we’ll dive into the Array indices as defined by the spec. Then you’ll understand why the confusing code below works.

let arr = [1,2,3];
arr['0']; // 1

The JavaScript spec identifies array elements if their keys meet the following requirements. A valid array index is transformed thus:

  1. All keys are strings.
  2. Convert the key to an unsigned 32-bit integer.
  3. Validate that the value is less than 232 – 1.
  4. Confirm that the original key is equivalent to the stringified version (i.e. x === x.toString() ).

Let’s Prove it!

// helper functions
let toUInt32 = x => x >>> 0;
let isLessThanMaxValue = x => 2**32 > x;
let stringifiedVersionsMatch = 
    x => toUInt32(x).toString() === x.toString();

>>> is the unsigned right shift operator. If you are interested in numeric operations in JavaScript; read A simple explanation of 1s complement arithmetic and working with integers in JavaScript.

1. Negative Numbers as indexes e.g. -2

// Convert to UInt32
toUInt32(-2);
// 4294967294

isLessThanMaxValue(toUint32(-2));
// true

stringifiedVersionsMatch(-2);
// false because '4294967294' !== '-2'

2. Zero i.e. 0

// Convert to UInt32
toUInt32(0);
// 0

isLessThanMaxValue(toUint32(0));
// true

stringifiedVersionsMatch(-2);
// true because '0' === '0'

3. Very large number i.e. 232 + 1

let value = 2**32 +1;

// Convert to UInt32
toUInt32(value);
// 1

isLessThanMaxValue(toUint32(value));
// true

stringifiedVersionsMatch(value);
// false because '4294967297' === '1'

4. A decimal number e.g. 3.4

let value = 3.4;

// Convert to UInt32
toUInt32(value);
// 3

isLessThanMaxValue(toUint32(value));
// true

stringifiedVersionsMatch(value);
// false because '3.4' === '3'

5. A string e.g. ‘abc”

let value = 'abc';

// Convert to UInt32
toUInt32(value);
// 0

isLessThanMaxValue(toUint32(value));
// true

stringifiedVersionsMatch(value);
// false because 'abc' === '0'

To simplify, valid indexes are:

  1. In the integer interval [0 .. 232-1].
  2. Non-negative.

If the index value does not pass the rules; it transforms into an object property.

Summary

Indices are strings interpreted as object keys and only seen as element indices once they meet the specifications. Otherwise, they are interpreted as object properties.

JavaScript arrays are objects. You can imagine arrays as special objects with indices instead of properties. These indices can point to arbitrary values (JavaScript is dynamically typed) and some of their distinguishing characteristics are:

  1. Indexes are special property keys which are natural numbers less than 2^32-1.
  2. All arrays have a length property which is 1 + the index of the last element.

Processing…
Awesome!

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 )

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.