josh oertel

javascript arrays are objects with numeric keys

There’s nothing special about arrays in JavaScript. They’re really just objects and all objects support bracket notation.

Take the object below.

const character = {
age: 38,
name: "Spongebob",
};

We all know you can access properties of this object through dot notation.

character.age; // 38
character.name; // "Spongebob"

You can also access the properties through bracket notation.

character["age"]; // 38
character["name"]; // "Spongebob"

Using bracket notation looks a lot like how you access elements in an array.

const names = ["Spongebob", "Plankton", "Squidward"];
names[0]; // "Spongebob"
names[1]; // "Plankton"
names[2]; // "Squidward"

You might think, “Hey this isn’t the same. Arrays use bracket notation with numbers not strings.” But have you ever tried bracket notation with strings on arrays?

names["0"]; // "Spongebob"
names["1"]; // "Plankton"
names["2"]; // "Squidward"
names["length"]; // undefined

Maybe surprisingly, it’s the same results as before. Believe it or not, the value put inbetween the brackets is actually stringified before the property access is carried out.

Most things in JS have a .toString method. As expected, toString when called on a number, returns a string representation of that number.

const zero = 0;
zero.toString(); // "0"
`${zero}`; // "0"

this is true even for immediate values

(0).toString() // "0"
`${0}`; // "0"

When accessing elements in an array, the index is stringfied before the access occurs.

names[0] === names["0"]; // true

This implies that arrays are really just objects with keys that look like numbers.

The next question would be, “Can you make an object that behaves like an array?” The answer is yes.

const names = {
0: "Spongebob",
1: "Plankton",
2: "Squidward",
};
names[0]; // "Spongebob"
names[1]; // "Plankton"
names[2]; // "Squidward"

Can you use Array’s methods on this object? The answer is kinda.

Arrays have methods on their prototype. Methods like map, reduce, and even properties like length are not available on the object unless it extends from array. However, these methods can still be called on something that is array-like if the prototype is used directly.

In this case, to be array-like requires the object to have a length property.

names.length = 3;

Now the Array’s prototype can be used with the object.

Array.prototype.map.call(names, (name) => name.substring(0, 1)); // ["S", "P", "S"]
Array.prototype.toReversed.call(names); // [ "Squidward", "Plankton", "Spongebob" ]
Array.prototype.reverse.call(names); // { 0: "Squidward", 1: "Plankton", 2: "Spongebob", length: 3 }

Interestly, methods that modify the instance such as reverse and sort keep the look and feel of the original object.

Conclusion

Knowing that arrays are really just objects probably won’t provide much in the way of understanding but it might be useful for very obscure and unconventional things.