Array.prototype.keys()

Returns an iterator over every index of the array, including empty slots.

Signature
keys()
  • Added in JavaScript ECMAScript 2015

Return value

Array IteratorA new iterable iterator object yielding each integer index from 0 to length - 1.

Errors

Throws a TypeError only if called on null or undefined.

keys() yields the numbers 0 through length - 1 as an iterator. It is the index half of the trio with values() and entries().

When to reach for it

Two situations. First, iterating indexes with for...of and break support, which forEach() does not offer. Second — and more common in practice — generating a range: [...Array(5).keys()] is [0, 1, 2, 3, 4], and it works because keys() is driven by length rather than by which indexes actually exist.

What trips people up

  • It is not Object.keys(). Object.keys() returns string keys and skips holes; keys() returns numbers and includes every index in range. For ["a", , "c"] you get ["0", "2"] versus [0, 1, 2].
  • The iterator is single-use. Once exhausted, a second for...of over the same iterator yields nothing.
  • It reads length on each step, so appending during iteration extends the loop and truncating ends it early.
  • If you need the index and the value, entries() saves a lookup.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Generate a numeric range with [...Array(n).keys()].
  • Loop over indexes with for...of so you can break or continue.
  • Walk every index of a sparse array, holes included.
  • Build a list of positions to feed into another lookup table.

Frequently asked questions

How do I create a range of numbers in JavaScript?

Use [...Array(n).keys()] to get 0 through n-1 as an array. Array.from({length: n}, (_, i) => i + start) is the version to reach for when the range does not start at zero.

What is the difference between Array.prototype.keys() and Object.keys()?

Array.prototype.keys() returns an iterator of numeric indexes covering the full length, holes included, while Object.keys() returns an array of string property names and skips empty slots. They disagree on any sparse array.

Can I reuse the iterator returned by keys()?

No, it is a one-time object: once it is exhausted, further iteration yields nothing. Call keys() again for a fresh iterator, or spread it into an array if you need to traverse the indexes more than once.

More examples

Ranges without a loop

Array(n) creates n empty slots, and keys() still yields an index for each because it only consults length. The Array.from version produces the same output and is the clearer choice when you also want to transform each index.

Example · javascript
const range = (n) => [...Array(n).keys()];
console.log(range(6));

// Shifted or scaled ranges
console.log(range(5).map((i) => i + 1));
console.log(range(4).map((i) => i * 10));

// Equivalent with Array.from
console.log(Array.from({ length: 4 }, (_, i) => i));

The iterator is consumed once

The first next() takes index 0, the spread drains the remaining 1 and 2, and the second spread finds nothing left. An exhausted iterator keeps returning done: true forever.

Example · javascript
const it = ["x", "y", "z"].keys();

console.log(it.next());
console.log([...it]);
console.log([...it]);
console.log(it.next());

Breaking out of an index loop

for...of over keys() supports break, so the loop stops at index 2 and never inspects the last two elements. forEach() would have to run to completion.

Example · javascript
const data = [4, 8, 15, 16, 23];

for (const i of data.keys()) {
  if (data[i] > 14) {
    console.log("first big value at index", i);
    break;
  }
  console.log("checked index", i);
}

Discussion

  • Be the first to comment on this lesson.