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)
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.