javascriptfor-loopforeachcounter

Get loop counter/index using for…of syntax in JavaScript


I understand that the basic for...of syntax in JavaScript looks like this:

for (let obj of myArray) {
  // ...
}

But how do I get the loop counter/index when iterating with this syntax?

(With the same question applying to for...in notation for iterating over object property names)

I know I can use an explicit loop counter like:

for (let i = 0; i < myArray.length; i++) {
  const obj = myArray[i];
  console.log(i);
}

Or manually track the index outside of the loop:

let i = 0;
for (let obj of myArray) {
  console.log(i);
  i++;
}

But I would rather use the simpler for...of loop, I think they look better and make more sense.

As an example of a language that lets you do this, in Python it's as easy as:

for i, obj in enumerate(my_array):
    print(i)

Solution

  • for…in iterates over property names, not values (and did so in an unspecified order up until ES2020*). You shouldn’t use it to iterate over arrays. For them, there’s ES5’s forEach method that passes both the value and the index to the function you give it:

    var myArray = [123, 15, 187, 32];
    
    myArray.forEach(function (value, i) {
        console.log('%d: %s', i, value);
    });
    
    // Outputs:
    // 0: 123
    // 1: 15
    // 2: 187
    // 3: 32
    

    Or ES6’s Array.prototype.entries, which now has support across current browser versions:

    for (const [i, value] of myArray.entries()) {
        console.log('%d: %s', i, value);
    }
    

    For iterables in general (where you would use a for…of loop rather than a for…in), there’s nothing built-in, however:

    function* enumerate(iterable) {
        let i = 0;
    
        for (const x of iterable) {
            yield [i, x];
            i++;
        }
    }
    
    for (const [i, obj] of enumerate(myArray)) {
        console.log(i, obj);
    }
    

    If you actually did mean for…in – enumerating properties – you would need an additional counter. Object.keys(obj).forEach could work, but it only includes own properties; for…in includes enumerable properties anywhere on the prototype chain.

    * The order is still unspecified under certain circumstances, including for typed arrays, proxies, and other exotic objects, as well as when properties are added or removed during iteration.