753

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)
2
  • 11
    Don't use for...in for arrays. And anyways, it iterates over the property names, not the values of the properties. Commented Apr 16, 2012 at 18:49
  • 4
    It's an array, not an object, right? So, alert(obj)? Commented Apr 16, 2012 at 18:49

12 Answers 12

1216

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 ES6’s Array.prototype.entries, which now has support across current browser versions:

const myArray = [123, 15, 187, 32];

for (const [i, value] of myArray.entries()) {
  console.log(`${i}: ${value}`);
}

// 0: 123
// 1: 15
// 2: 187
// 3: 32
.as-console-wrapper { max-height: 100% !important; top: 0; border-top: 0 !important; }

Or, for extended compatibility with older browsers, there’s ES5’s forEach method that passes both the value and the index to the function you give it:

myArray.forEach(function (value, i) {
  console.log('%d: %s', i, value);
});

For iterables in general (where you would use a for…of loop rather than a for…in), iterator helpers are now in the language. You can use Iterator.prototype.forEach to iterate over an entire iterable with an index:

function* fibonacci() {
  let a = 0;
  let b = 1;

  for (;;) {
    yield a;
    [a, b] = [b, a + b];
  }
}

fibonacci().take(10).forEach((x, i) => {
  console.log(`F_${i} = ${x}`);
});
.as-console-wrapper { max-height: 100% !important; top: 0; border-top: 0 !important; }

More generally, Iterator#map can associate the values yielded by an iterator with their indexes:

fibonacci().map((x, i) => [i, x])

Not every iterable (or iterator!) is an Iterator, but you can convert every iterable to an Iterator with Iterator.from.

Without support for iterator helpers, you can use a generator function instead:

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.

Sign up to request clarification or add additional context in comments.

9 Comments

Actually, obj will be the array index, but there is no guarantee that it is in order and that it won't include other property names.
stupid question but what does %d and %s actually stand for, or could they be any letter I want them to be?
@klewis: %d formats an integer and %s formats a string. They’re inspired by printf. A spec is in progress at console.spec.whatwg.org/#formatter.
The downside of forEach is that await inside is scoped to the function parameter, not the outer scope. So if you want to await inside the loop, you probably want to use .entries().
@merlindru: I’ve updated the answer to account for changes added in newer specs.
|
491

In ES6, it is good to use a for... of loop. You can get index in for... of like this

for (let [index, val] of array.entries()) {
  // your code goes here    
}

Note that Array.entries() returns an iterator, which is what allows it to work in the for-of loop; don't confuse this with Object.entries(), which returns an array of key-value pairs.

10 Comments

I think this solution is better than the forEach one... It uses the nomral for...of loop syntax, and you don't have to use a separate function. In other words, it's syntactically better. The OP seems to have wanted this.
entries() is returning an empty object: {}. Any idea why that would be? My array is an Array of Objects.
It's supposed to do that, Joshua - the object is an iterator, an object with a next() method that will return subsequent entries in the array each time it is called. There's no (visible) data in it; you get the data in the underlying object by calling next(), which for-of does behind the scenes. cc @tonyg
Also this allows await to work in sequence, whereas forEach does not.
Be aware this only works for Array. for...of works on any Iterable. You might have to convert to Array with for (const [index, value] of [...array].entries()). Iterables include HTMLCollection NodeList, and other DOM classes.
|
56

How about this

let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log(`${index}:${number}`))

Where array.forEach this method has an index parameter which is the index of the current element being processed in the array.

3 Comments

The chosen answer was posted 6 years before this one and has the same thing already in it...
Foreach is not good for optimization, since break is not available.
@smartworld-dm I do agree with this but there is the simple return statement.
19

Solution for small array collections:

for (var obj in arr) {
    var i = Object.keys(arr).indexOf(obj);
}

arr - ARRAY, obj - KEY of current element, i - COUNTER/INDEX

Notice: Method keys() is not available for IE version <9, you should use Polyfill code. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

17 Comments

I'd suggest: use a counter instead, increment it in loop.
Adding on to mayankcpdixit, use a counter instead because indexOf could have a negative performance impact.
The larger the object, the slower this will get. This does not scale.
This is kind of pointlessly slow and complicated because var i = 0; and i++; is shorter and more efficient. Plus it doesn't work for enumerable properties that aren't own properties.
@trusktr: And if it is required… you should still not use this. Just alter the counter when you alter the collection. If it doesn’t have to be in-place, do a nice functional transformation instead.
|
18

For-in-loops iterate over properties of an Object. Don't use them for Arrays, even if they sometimes work.

Object properties then have no index, they are all equal and not required to be run through in a determined order. If you want to count properties, you will have to set up the extra counter (as you did in your first example).

loop over an Array:

var a = [];
for (var i=0; i<a.length; i++) {
    i // is the index
    a[i] // is the item
}

loop over an Object:

var o = {};
for (var prop in o) {
    prop // is the property name
    o[prop] // is the property value - the item
}

7 Comments

Never do (var i=0; i<a.length; i++) as is wasted resources. Use (var i=0, var len = a.length; i<len; i++)
@FelixSanz: Waste resources? No way. That is a premature micro-optimisation that is hardly ever necessary, and var i=0; i<a.length; i++) is the standard loop pattern that is optimised by every decent javascript engine anyway.
@FelixSanz: Yes, and var i=0; i<a.length; i++ is the best practise.
KISS. If you write loops where you really need this you either are doing something wrong, or you have a better argument for its necessity than "best practise". Yes, it is a standard practise, but not for generic performance optimisation, but only for micro-optimisation.
KISS applies everywhere. Premature optimisation is an anti-practise.
|
12

As others have said, you shouldn't be using for..in to iterate over an array.

for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }

If you want cleaner syntax, you could use forEach:

myArray.forEach( function ( val, i ) { ... } );

If you want to use this method, make sure that you include the ES5 shim to add support for older browsers.

Comments

7

Answer Given by rushUp Is correct but this will be more convenient

for (let [index, val] of array.entries() || []) {
   // your code goes here    
}

4 Comments

|| [] is unnecessary and will never be used; array.entries() is always truthy.
[index, val] never works for me, it says "undefined"
can you share your array ?
Why repeat an existing answer? Downvoted.
2

Here's a function eachWithIndex that works with anything iterable.

You could also write a similar function eachWithKey that works with objets using for...in.

// example generator (returns an iterator that can only be iterated once)
function* eachFromTo(start, end) { for (let i = start; i <= end; i++) yield i }

// convers an iterable to an array (potential infinite loop)
function eachToArray(iterable) {
    const result = []
    for (const val of iterable) result.push(val)
    return result
}

// yields every value and index of an iterable (array, generator, ...)
function* eachWithIndex(iterable) {
    const shared = new Array(2)
    shared[1] = 0
    for (shared[0] of iterable) {
        yield shared
        shared[1]++
    }
}

console.log('iterate values and indexes from a generator')
for (const [val, i] of eachWithIndex(eachFromTo(10, 13))) console.log(val, i)

console.log('create an array')
const anArray = eachToArray(eachFromTo(10, 13))
console.log(anArray)

console.log('iterate values and indexes from an array')
for (const [val, i] of eachWithIndex(anArray)) console.log(val, i)

The good thing with generators is that they are lazy and can take another generator's result as an argument.

Comments

2

On top of the very good answers everyone posted I want to add that the most performant solution is the ES6 entries. It seems contraintuitive for many devs here, so I created this perf benchamrk.

enter image description here

It's ~6 times faster. Mainly because doesn't need to: a) access the array more than once and, b) cast the index.

4 Comments

I've got to say you are not comparing apple to apple in the above test case. In classic, extra const v is defined plus the unnecessary type conversion Number(i) all led to its overhead. By removing those bits, my result shows the contrary: classic is 4 times faster. Please check the updated version here
@Marshal Your link is dead
@javadba, That's because jsperf is down. I'll create a new answer
Saying it’s the “most performant solution” based on a benchmark that only includes one other approach (that also happens to be wrong) is pretty misleading. How about comparing it against the top answers?
2

That's my version of a composite iterator that yields an index and any passed generator function's value with an example of (slow) prime search:

const eachWithIndex = (iterable) => {
  return {
    *[Symbol.iterator]() {
      let i = 0
      for(let val of iterable) {
        i++
          yield [i, val]
      }
    }
  }

}

const isPrime = (n) => {
  for (i = 2; i < Math.floor(Math.sqrt(n) + 1); i++) {
    if (n % i == 0) {
      return false
    }
  }
  return true
}

let primes = {
  *[Symbol.iterator]() {
    let candidate = 2
    while (true) {
      if (isPrime(candidate)) yield candidate
        candidate++
    }
  }
}

for (const [i, prime] of eachWithIndex(primes)) {
  console.log(i, prime)
  if (i === 100) break
}

2 Comments

Why do you have a function eachWithIndex[Symbol.iterator] instead of just a function eachWithIndex? eachWithIndex doesn’t satisfy the iterable interface, which is the whole point of Symbol.iterator.
@Ry- Good catch, changed eachWithIndex to accept iterable and return a closured composite iterable.
-3
// this loop is used in advanced javascript
//For Example I have an array:
let array = [1,2,3,4,5];
1) for(let key in array){
      console.log(key);//this shows index of array {Result: 0,1,2,3,4}
      console.log(array[key]);//this show values of array {Result: 1,2,3,4,5}
   }
//Hopefully, You will quickly understand;

Comments

-3

One answer that seems to be missing is that in Python, the enumeration is a function. So: you could just do the same in JavaScript and then destructure during your for...of loop:

// Stick this in any random utils.js that you can import from
function enumerate(arr) {
  return arr.map((element, i) => [i, element]);
}

const myArray = ['a','b','c','d','e'];

// And then loop over *that* instead of the plain array:
for (let [i, element] of enumerate(myArray)) {
  console.log(i, element);
}

But I'd probably go with a map instead, of course: does the same as forEach, except if you ever need to capture the transformed result in the future, you're already using the right function.

myArray.forEach((element, i) => {
  console.log(i, element);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.