Arrays are objects
First, let's confirm that arrays are objects.
This is key to understanding how they work:
const arr = ['a', 'b', 'c']
// Under the hood, it's like this:
const arrAsObject = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
}
// We can prove this
typeof [] // "object"
[] instanceof Object // true
Arrays special behaviors
Arrays have some special behaviors that regular objects don't:
// 1. Length is automatically managed
const arr = ["a"];
arr[1] = "b";
console.log(arr.length); // 2
// 2. Indices are converted to strings
arr["2"] = "c"; // Same as arr[2] = 'c'
console.log(arr); // ['a', 'b', 'c']
// 3. You can add non-index properties
arr.customProp = "hello";
console.log(arr.customProp); // "hello"
console.log(arr.length); // Still 3 (properties don't count)
Array length
The length property is special:
const arr = ["a", "b", "c"];
arr.length = 1; // Truncates the array!
console.log(arr); // ['a']
arr.length = 3; // Extends with empty slots
console.log(arr); // ['a', empty × 2]
Sparse arrays
Sparse arrays (arrays with holes) are possible because of this object nature:
const sparse = [];
sparse[0] = "first";
sparse[2] = "third";
console.log(sparse); // ['first', empty, 'third']
console.log(sparse.length); // 3
// Empty slots are different from undefined
sparse[1] = undefined;
console.log(0 in sparse); // true
console.log(1 in sparse); // true
console.log(3 in sparse); // false
Prototype
Array methods exist on Array.prototype:
const arr = ["a", "b"];
console.log(arr.__proto__ === Array.prototype); // true
console.log(arr.__proto__.__proto__ === Object.prototype); // true
This object-like nature affects performance:
// V8 can optimize sequential, numeric properties
const optimized = ["a", "b", "c"];
// But mixing types or adding non-index properties can deoptimize
optimized.prop = "bad";
optimized[0.5] = "worse"; // Non-integer index
If you wanna learn more about JS internals, read: How to write performant JavaScript code.
And finally, this is why array-like objects exist.
They mimic this structure:
const arrayLike = {
0: "a",
1: "b",
length: 2,
};
// We can convert it to a real array
const realArray = Array.from(arrayLike);
// Or
const alsoReal = [...arrayLike]; // If it's iterable
This object nature of arrays explains many JavaScript behaviors:
Why we can add properties to arrays
Why array lengths can be manipulated
Why sparse arrays are possible
Why array-like objects work
How prototype inheritance works for arrays
The JavaScript engine optimizes common array patterns, but knowing that arrays are objects helps us understand their flexibility and limits.
More on the JS engine
// V8 has different ways it stores arrays internally based on how we use them
// 1. The fastest: packed elements
const packed = [1, 2, 3] // Sequential, same type (all numbers)
// V8 can store this in continuous memory blocks
// Direct memory access, very fast
// 2. Still fast: holey elements
const holey = [1, , 3] // Has a hole
// V8 needs extra checks when accessing elements
// Must check if element exists
// 3. Slower: mixed elements
const mixed = [1, "string", 3] // Different types
// V8 can't optimize as well
// Must handle different types
// Even slower patterns:
const bad1 = []
bad1[1000] = 1 // Creates sparse array
// V8 switches to dictionary mode (hash table)
const bad2 = [1, 2, 3]
bad2.foo = 'bar' // Non-index property
// Can force V8 to switch to a slower mode
V8 has specific array modes:
PACKED_SMI
: All small integersPACKED_DOUBLE
: All doublesPACKED_ELEMENTS
: All same typeHOLEY_SMI
: Small integers with holesHOLEY_ELEMENTS
: Mixed with holes
Every time we do something that doesn't match the current mode, V8 has to switch to a more general (slower) mode. It can't switch back to a faster mode.
const arr = [1, 2, 3] // Starts as PACKED_SMI
arr.push(4.5) // Transitions to PACKED_DOUBLE
arr.push("string") // Transitions to PACKED_ELEMENTS
delete arr[1] // Transitions to HOLEY_ELEMENTS
This is why performance-critical code often:
Sets the array size in advance
Keeps arrays full (no holes)
Uses the same types
Avoids adding properties that aren't indexed