286

We can access array elements using a for-of loop:

for (const j of [1, 2, 3, 4, 5]) {
  console.log(j);
}

How can I modify this code to access the current index too? I want to achieve this using for-of syntax, neither forEach nor for-in.

Abdennour TOUMI
  • 64,884
  • 28
  • 201
  • 207

12 Answers12

425

Use Array.prototype.keys:

for (const index of [1, 2, 3, 4, 5].keys()) {
  console.log(index);
}

If you want to access both the key and the value, you can use Array.prototype.entries() with destructuring:

for (const [index, value] of [1, 2, 3, 4, 5].entries()) {
  console.log(index, value);
}
Christophe Marois
  • 5,513
  • 1
  • 23
  • 23
Michał Perłakowski
  • 70,955
  • 24
  • 137
  • 155
  • 77
    In case someone wonders, I tested `for-of` with `.entries()` and it's twice as slow compared to `.forEach()`. https://jsperf.com/for-of-vs-foreach-with-index –  Sep 25 '17 at 06:14
  • 1
    @K48 nice to know, use "reversed for-loop" if you want to have the fastest in es: https://www.incredible-web.com/blog/performance-of-for-loops-with-javascript/ – nimo23 Jan 15 '18 at 19:11
  • 4
    Unfortunately, I need to yield from inside a nested loop. Can't use forEach, because the function creates scope problems for the `yield` keyword. But I need access to the index for my use case, so... basic old `;;` loop it is, I guess. – Kyle Baker Feb 09 '18 at 21:19
  • 2
    @KyleBaker And what's wrong with a for-of loop with `.entires()`? – Michał Perłakowski Feb 09 '18 at 21:58
  • I presume it would also not be performant, but it certainly wouldn't be necessary. You can use it if you like, but the nature of a standard for loop is that one has 'access' to both the index and value in a very straightforward manner. With a for-of, one would _need_ `.entries()` to have access to the index. – Kyle Baker Feb 09 '18 at 22:10
  • 1
    Instead reverse loop you may cache length https://jsperf.com/reverse-loop-vs-cache. For-of usefull for iterable processing when you able to process stream without creating big arrays in RAM. Loop speed wouldn't be bottleneck since you will have I/O latency in such cases. – x'ES Feb 19 '18 at 12:17
  • Does it work even though we're cycling an HTMLCollection? – Rickyx Jun 17 '20 at 00:55
327

Array#entries returns the index and the value, if you need both:

for (let [index, value] of array.entries()) {

}
Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072
  • 3
    With TypeScript: 'TS2495: Type IterableIterator is not an array type or a string type'. Seems like this will be solved: https://github.com/Microsoft/TypeScript/pull/12346 – Johannes Mar 08 '17 at 08:31
  • 2
    Also Internet Explorer not supported. – Sammi Mar 24 '17 at 11:34
  • 1
    Not nice. Throws an error e.g. with `document.styleSheets[0].cssRules.entries()` or even `document.styleSheets.entries()` and probably many other DOM iterable structures. Still have to use `_.forEach()` from `lodash` – Steven Pribilinskiy Jun 07 '17 at 20:24
  • 2
    @Steven: If you don't need the index, you can just do `for (var value of document.styleSheets) {}`. If you do need the index you can convert the value to an array first via `Array.from`: `for (let [index, value] of Array.from(document.styleSheets)) {}`. – Felix Kling Jun 07 '17 at 22:14
  • 1
    That's nice! `Array.from` is FTW – Steven Pribilinskiy Jun 10 '17 at 23:34
  • Instead of complaining about which browsers support what, write in ES6 and transpile down to ES5. Write once, DRY, KISS... – pmont Jun 20 '17 at 18:36
59

In this world of flashy new native functions, we sometimes forget the basics.

for (let i = 0; i < arr.length; i++) {
    console.log('index:', i, 'element:', arr[i]);
}

Clean, efficient, and you can still break the loop. Bonus! You can also start from the end and go backwards with i--!

Additional note: If you're using the value a lot within the loop, you may wish to do const value = arr[i]; at the top of the loop for an easy, readable reference.

chris
  • 1,571
  • 15
  • 17
  • 1
    Yep. Good one, clear and simple. Oh, and like that you have a super easy way to access the key/index of the array. – Combine Oct 10 '18 at 07:56
  • 2
    By the way the condition should look like this -> for (let i = 0; i < arr.length; i++) without the (-1) or it will not loop throughout all the elements of the array. – Combine Oct 10 '18 at 08:06
  • 1
    @Combine Good catch! I have updated my answer to reflect your note. – chris Oct 11 '18 at 19:45
  • 4
    You can still `break` a `for-of` and `for (let [index, value] of array.entries())` is far easier to read. Going backwards is as easy as adding `.reverse()`. – Nigel B. Peck Oct 28 '18 at 03:19
  • 1
    This does not answer the question in any way. It would be nice in a comment (basics are always important), but not here. – user3658510 Oct 10 '19 at 23:15
  • 1
    I don't think this answers the particular question, but you are completely right that this is a good way to do it. – Filip Cordas Oct 10 '19 at 23:34
  • 4
    I think this is a perfectly acceptable answer to this question. It will never be the accepted answer but it has helped a few dozen people or more who have searched for this question. This is what SO is for. – Danoram Oct 11 '19 at 00:31
  • 1
    The simple `for` loop is ~8 times faster than the `for of array.entries()`. https://jsbench.me/6dkh13vqrr/1 – Henrique Bruno Nov 02 '20 at 22:20
6

You can also handle index yourself if You need the index, it will not work if You need the key.

let i = 0;
for (const item of iterableItems) {
  // do something with index
  console.log(i);

  i++;
}
TintinSansYeux
  • 703
  • 8
  • 25
5

In a for..of loop we can achieve this via array.entries(). array.entries returns a new Array iterator object. An iterator object knows how to access items from an iterable one at the time, while keeping track of its current position within that sequence.

When the next() method is called on the iterator key value pairs are generated. In these key value pairs the array index is the key and the array item is the value.

let arr = ['a', 'b', 'c'];
let iterator = arr.entries();
console.log(iterator.next().value); // [0, 'a']
console.log(iterator.next().value); // [1, 'b']

A for..of loop is basically a construct which consumes an iterable and loops through all elements (using an iterator under the hood). We can combine this with array.entries() in the following manner:

array = ['a', 'b', 'c'];

for (let indexValue of array.entries()) {
  console.log(indexValue);
}


// we can use array destructuring to conveniently
// store the index and value in variables
for (let [index, value] of array.entries()) {
   console.log(index, value);
}
Willem van der Veen
  • 19,609
  • 11
  • 116
  • 113
4

in html/js context, on modern browsers, with other iterable objects than Arrays we could also use [Iterable].entries():

for(let [index, element] of document.querySelectorAll('div').entries()) {

    element.innerHTML = '#' + index

}
Joseph Merdrignac
  • 2,212
  • 2
  • 16
  • 16
  • Yes this works, whereas other mentioned above by @Steven Pribilinskiy other DOM methods return objects that don't have an `entries` method for them. – matanster Jan 24 '19 at 09:46
1

Another approach could be using Array.prototype.forEach() as

Array.from({
  length: 5
}, () => Math.floor(Math.random() * 5)).forEach((val, index) => {
  console.log(val, index)
})
Saksham
  • 8,110
  • 6
  • 35
  • 63
0

For those using objects that are not an Array or even array-like, you can build your own iterable easily so you can still use for of for things like localStorage which really only have a length:

function indexerator(length) {
    var output = new Object();
    var index = 0;
    output[Symbol.iterator] = function() {
        return {next:function() {
            return (index < length) ? {value:index++} : {done:true};
        }};
    };
    return output;
}

Then just feed it a number:

for (let index of indexerator(localStorage.length))
    console.log(localStorage.key(index))
Hashbrown
  • 8,877
  • 7
  • 57
  • 71
0

es6 for...in

for(const index in [15, 64, 78]) {                        
    console.log(index);
}
solanki...
  • 3,969
  • 2
  • 21
  • 29
  • 6
    The question is asking about a `for...of` loop not a `for...in` – abranhe May 15 '19 at 17:37
  • 3
    `for...in` is part of the original ECMAScript specification (i.e."es1") . Also, note that `for...in` is meant for iterating over object properties. While it can iterate over arrays, it may not do so in the expected order. See more in the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) – Boaz Dec 24 '19 at 22:02
0

Also you can use JavaScript to solve your problem

iterate(item, index) {
    console.log(`${item} has index ${index}`);
    //Do what you want...
}

readJsonList() {    
    jsonList.forEach(this.iterate);
    //it could be any array list.
}   
0

Just create a variable before the loop and assign an integer value.

let index = 0;

and then use addition assignment operator into the loop scope

index += 1;

That's It, check the below snippet example.

let index = 0;
for (const j of [1, 2, 3, 4, 5]) {
  index += 1;
  console.log('index ',index);
}
Hidayt Rahman
  • 1,798
  • 22
  • 27
-7
const fruits = ["apple","pear","peach"];
for (fruit of fruits) {
    // TODO remove before commit to avoid decrease of performance
    const i = fruits.indexOf(fruit);
    console.log(i)
    //it shows the index of every fruit from fruits, should be used only on development and debug process 
}

The for loop traverses the array, while the indexof property takes the value of the index that matches the array. P.D this method has some flaws with numbers, so use fruits

Pablo Palacios
  • 2,394
  • 15
  • 33
  • 2
    This takes O(n^2) time. – Harry Dec 16 '18 at 10:21
  • 5
    In cases where performance is not important, this still does not give all the correct indexes when there are duplicate fruit. For example, for `["apple", "apple", "pear"]` the indexes given are `0, 0, 2` instead of `0, 1, 2`. – trichoplax Mar 24 '19 at 15:26
  • I think this shouldn't be voted down, but needs explanation. It does increase complexity, so it should not be used in production. But it can be used while developing or debugging on the console to test specific scenarios and in those cases, where I don't want to use entries that will be a permanent modification. – Pablo Palacios Mar 18 '21 at 15:43