Get the index in a JavaScript for-of loop

By

Learn how to get the index of the current iteration in a JavaScript for-of loop by calling the array entries() method with destructuring syntax.

~~~

To get the index of the current iteration in a for-of loop, call the entries() method on the array, and destructure each entry into index and value:

for (const [i, v] of ['a', 'b', 'c'].entries()) {
  console.log(i, v)
}
//0 a
//1 b
//2 c

Let’s see why this works. A for-of loop, introduced in ES6, is a great way to iterate over an array:

for (const v of ['a', 'b', 'c']) {
  console.log(v)
}

The loop gives you each value, but no index. It does not offer any syntax to get it.

How does entries() help?

entries() returns an iterator. Each item it produces is a 2-element array: the index first, then the value.

const letters = ['a', 'b', 'c']

for (const entry of letters.entries()) {
  console.log(entry)
}
//[ 0, 'a' ]
//[ 1, 'b' ]
//[ 2, 'c' ]

The destructuring syntax, also introduced in ES6, unpacks each pair into two variables right in the loop head. That’s what const [i, v] does in the first example.

Notice that entries() does not build a new array of pairs upfront. It’s an iterator, so pairs are produced one at a time as the loop runs. Iterating a big array this way costs almost nothing extra.

The names i and v are just a convention. Pick descriptive ones when it helps, like const [index, day] when looping over weekdays.

Why not just use forEach()?

forEach() passes the index to the callback as the second argument:

['a', 'b', 'c'].forEach((v, i) => {
  console.log(i, v)
})

That works, and it’s shorter. But for-of can do things the callback can’t. You can stop early with break, skip an iteration with continue, and use await inside the loop body and have it pause the iteration. An await inside a forEach() callback does not pause the loop.

My advice: when you’re already inside a for-of loop and discover you need the index, add entries() and destructure. No need to restructure the loop.

Watch out for non-arrays

entries() is an array method. Strings are iterable with for-of, but they don’t have it:

for (const [i, c] of 'hey'.entries()) {
}
//TypeError: "hey".entries is not a function

The fix is spreading the string into an array first:

for (const [i, c] of [...'hey'].entries()) {
  console.log(i, c)
}
//0 h
//1 e
//2 y
~~~

Related posts about js: