Detecting missing elements
Testing whether an index is present rather than merely reading as undefined.
JS Puzzles · Const
Array holes are missing indexed properties, not stored undefined values. They make an array sparse, and different operations either skip the missing positions or expose them as undefined.
An array hole is an absent indexed property, not an element whose value is undefined. Holes can arise from omitted literal entries, Array(length), or assigning beyond the current end; some operations treat them as undefined, while many array iteration methods skip them.
const sparse = [value, , value];
const empty = Array(length);const holes = [1, , 3];
const undefinedValue = [1, undefined, 3];
console.log(holes.length); // 3
console.log(holes[1]); // undefined
console.log(holes.hasOwnProperty(1)); // false
console.log(undefinedValue.hasOwnProperty(1)); // true
holes.forEach((value) => console.log(value)); // 1, 3
for (const value of holes) console.log(value); // 1, undefined, 3A hole has no property at its index, although indexed access produces undefined. Array iteration methods such as forEach skip holes, while for...of visits the position as undefined.
Testing whether an index is present rather than merely reading as undefined.
Predicting callback counts and results when processing partially populated arrays.
Representing index ranges with intentionally uninitialized positions.
A hole is a missing indexed property, whereas an explicit undefined value is an existing property containing undefined. Both usually produce undefined through indexed access, but hasOwnProperty or the in operator distinguishes them.
Follow-up: What happens with for...of? It visits the hole position and yields undefined, unlike forEach, which skips the missing property.
An array literal can omit an element between commas, such as [1, , 3]. Array(5) creates five empty slots, and assigning a far index creates holes between the old end and that index.
Follow-up: Why can a far index be surprising? It increases length to the assigned index plus one while leaving intervening indices absent.
Indexed access and for...of expose holes as undefined-like values, while forEach and map skip them. Therefore, array length does not indicate how many callbacks an iteration method will make.
Follow-up: How can you inspect actual present indices? Object.keys lists only existing properties, whereas Array.prototype.keys iterates every index position.
Array.prototype.forEach()Array.prototype.map()Array.prototype.keys()Array.prototype.slice()Array(length)