Array.prototype.keys()
keys() The keys() method returns a new Array iterator object containing the keys (indices) of each array element. Introduced in ES6, this method provides a clean way to iterate over array indices using for...of loops, avoiding the older for loop syntax.
Syntax
array.keys()
Takes no parameters and returns an iterator object. Unlike manually tracking an index variable, keys() produces indices on demand — the iterator is lazy and yields each position only when requested by the consuming loop or spread.
Parameters
None. The method accepts no parameters.
Examples
Basic usage with for…of
const fruits = ["apple", "banana", "cherry"];
for (const index of fruits.keys()) {
console.log(index);
}
// 0
// 1
// 2
The iterator from keys() can be spread into an array literal to capture all indices at once. This is useful when you need to pass the index sequence to array methods like map or filter that don’t work directly with iterators.
Using with spread operator
const numbers = [10, 20, 30];
const indices = [...numbers.keys()];
console.log(indices);
// [0, 1, 2]
keys() visits every integer index from 0 to length - 1, including positions that are holes in sparse arrays. This makes it more predictable than forEach or map when you are dealing with arrays that may have missing slots — you always get a complete index sequence regardless of whether a value exists at each position.
Working with sparse arrays
Unlike forEach(), keys() only iterates over indices that actually exist:
const sparse = [1, , 3];
console.log([...sparse.keys()]);
// [0, 1, 2]
A common pattern is iterating two arrays in lockstep by using keys() on one of them. This avoids a manual index counter and makes the relationship between the two arrays explicit — each iteration pulls the same-position element from both arrays.
Parallel array iteration
const names = ["Alice", "Bob", "Carol"];
const ages = [25, 30, 35];
for (const i of names.keys()) {
console.log(`${names[i]} is ${ages[i]} years old`);
}
// Alice is 25 years old
// Bob is 30 years old
// Carol is 35 years old
You can feed the indices into Array.from or a reduce to build index-keyed data structures. The example below turns a flat array into an object where each key is the numeric index, which can be useful for sparse lookups or when you need to preserve position alongside value.
Using Array.from with transformation
const data = ['a', 'b', 'c'];
// Create object with index as key
const indexed = Array.from(data.keys()).reduce((acc, i) => {
acc[i] = data[i];
return acc;
}, {});
console.log(indexed); // { 0: 'a', 1: 'b', 2: 'c' }
Spreading keys() into an array and then chaining array methods gives you a pipeline that selects positions by condition. This is a declarative alternative to building a result array with a for loop — the intent reads left to right: get all indices, keep the ones where the score meets the threshold.
Finding indices matching condition
const scores = [65, 90, 75, 82, 55];
const passingIndices = [...scores.keys()].filter(i => scores[i] >= 70);
console.log(passingIndices); // [1, 2, 3]
Once you have identified target indices, you can modify the original array in place by iterating over those positions. This two-step approach — first select, then mutate — keeps the selection logic separate from the update logic, making each step easier to test and reason about independently.
Practical: updating specific indices
const items = ['a', 'b', 'c', 'd', 'e'];
// Double values at even indices
const indicesToUpdate = [...items.keys()].filter(i => i % 2 === 0);
indicesToUpdate.forEach(i => {
items[i] = items[i] + items[i];
});
console.log(items); // ['aa', 'b', 'cc', 'd', 'ee']
The examples above show keys() used for iteration, but the method also enables a family of index-driven transformation patterns that go beyond simple loops. By spreading indices into an array, you can chain map, filter, and reduce to express transformations declaratively — no counter variables or manual index management needed.
Common Patterns
Reconstructing array with modifications
const original = [1, 2, 3, 4, 5];
const doubled = [...original.keys()].map(i => original[i] * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
Return value
keys() returns an Array Iterator object. This iterator is lazy — it does not pre-compute all indices but yields them one at a time as next() is called. The iterator’s Symbol.iterator method returns the iterator itself, making it usable directly in for...of without conversion.
What keys() returns
The Array.prototype.keys() method returns an iterator object, not an array. The iterator is consumed once — after spreading or completing a for...of loop, it is exhausted. To reuse the indices, call keys() again or convert to an array once with [...arr.keys()]. The iterator follows the standard iterator protocol: it has a next() method returning { value, done } objects.
keys() on sparse arrays
Unlike forEach, map, and filter, which skip over holes in sparse arrays, keys() yields every integer index from 0 to length - 1, including indices corresponding to holes. This makes keys() useful when you need to iterate all positions in a sparse array and distinguish between a hole and an explicitly set value.
const sparse = [1, , 3];
[...sparse.keys()]; // [0, 1, 2] — includes index 1 even though it's a hole
Beyond iterating actual arrays, keys() paired with Array(n) creates a lightweight integer sequence without a classic for loop. This trick works because the iterator produced by Array(n).keys() yields 0, 1, ..., n-1 regardless of what (if anything) is stored at each slot.
Generating index ranges
Array.prototype.keys() called on a pre-sized array-like is a common pattern for generating a range of integers without a traditional for loop:
const range = [...Array(5).keys()]; // [0, 1, 2, 3, 4]
const shifted = [...Array(5).keys()].map(i => i + 1); // [1, 2, 3, 4, 5]
Iterator lifecycle
The iterator returned by keys() is consumed once. Spread it or use it in a for...of loop, but do not try to iterate it twice — the second pass will find the iterator already exhausted and yield nothing. Call keys() again to get a fresh iterator when you need another pass.
See Also
- Array.prototype.values() — Iterate over values
- Array.prototype.entries() — Iterate over index-value pairs
- Map.prototype.forEach() — Execute a function for each element
- Array.prototype.map() — Transform each element