Josh Ellis

Posted on

Problems with Using for...in on Arrays in JavaScript

I've been doing a lot of algorithm practice lately, and I just came across a quirk of how for...in works.

I love using JavaScript's for...in and for...of loops when iterating because I consider the code much cleaner and readable at a glance.

In this post, I'll be discussing a problem you may run into with for...in if you're trying to take shortcuts like I was.

What is for...in?

In case you're not familiar, here's a simple example of code side by side that will give the same console logs:

``````arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]) // 1, 2, 3
}

for(let i in arr) {
console.log(arr[i]) // 1, 2, 3
}

for(let el of arr) {
console.log(el) // 1, 2, 3
}
``````

Like I said earlier, I consider the second/third to be "cleaner", but the second runs into issues if you need to use `i` as a number. The following won't produce the same console logs:

``````arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
n = i + 5
console.log(n) // 6, 7, 8
}

for(let i in arr) {
n = i + 5
console.log(n) // "05", "15", "25"
}
``````

The reason for this is because `typeof i` in the for...in loop is a `"string"` rather than a `"number"`. This means you'll get weird results doing math on `i`.

Conclusion

In summary, if you need to use the numerical value for the index as you loop over an array, you either need to use the long-form verbose/explicit for loop or add something like `i = parseInt(i)` at the top of your loop:

``````arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
n = i + 5
console.log(n) // 6, 7, 8
}

for(let i in arr) {
i = parseInt(i)
n = i + 5
console.log(n) // 6, 7, 8
}
``````

Edit: There have been a few other great suggestions on how to handle this in the comments! Check them out

You can also use `Array#keys` to get an iterator with the array indexes as numbers:

``````const arr = [1, 2, 3]

for (const i of arr.keys()) {
console.log(typeof i, i) // number 0, number 1, number 2
}
``````

Similarly, `Array#values` gives the elements of the array, and `Array#entries` gives tuples of `[index, element]`:

``````for (const [idx, el] of arr.entries()) {
console.log({ idx, el }) // {idx: 0, el: 1}, {idx: 1, el: 2}, {idx: 2, el: 3}
}
``````

Josh Ellis • Edited

Awesome! I didn't put 2 + 2 that `.keys()` and `.entries()` would work on arrays (I use them all the time for objects), that's great.

lionel-rowe

It's a little different from `Object.keys` and so on. You can do `Object.keys(arr)` too, but then you'll get an array of string keys, rather than an iterator of number keys. Interestingly, there's no such thing as `Object#keys` β I guess it doesn't make sense to return an iterator of keys for something that itself isn't iterable.

Josh Ellis

Right, because they're class methods on Object that take a param, that's probably why I didn't think to look into how it could work with arrays. Very interesting.

Josh Ellis • Edited

An alternative that I didn't want to get into is using the index param from `arr.forEach`, but it is an option:

``````arr = [1, 2, 3]
arr.forEach((el, idx) => {
n = idx + 5
console.log(n) // 5, 6, 7
})
``````

Srikanth

It's informative and straight to point..
Also if possible can you change examples for "What is for...in?" as

``````array = [4, "some text", true];

for (let i in array) {  //  in for..in 'i' returns index
console.log(i); // 0, 1, 2
console.log(typeof i); // string, string, string
console.log(array[i]); // 4, some text, true
}

for (const el of array) {   //  in for..of 'el' returns element
console.log(el);  // 4, some text, true
console.log(typeof el);   // number, string, boolean
}
``````

Anyways..thanks for the information

Josh Ellis

Thanks for the extra info!

Vamp • Edited

the reason for this is that βfor...inβ iterates over all the enumerable (own, not proto) properties of the object. this means that the array object (subject) will have its properties (index values) iterated over.

the reason they are a string is because all object properties are stored as strings. the properties of an array are indices which are presented as strings just as any other object properties.

you can use Object(arr).entries as the iterator which will give you [index, element] pairs in βfor...ofβ. because βfor...ofβ iterates over the elements themselves which will be those entry pairs.

Josh Ellis

Thanks for the extra details! Makes sense that is just like object properties note that you mention it

Good read ... who knows a mnemonic or aid to help remembering the difference between "for in" and "for of"? because I always forget which is which ...

Ah got it already - I think this would work:

for "I"n yields "I"ndexes
for "O"f yields "O"bjects

So "for In" yields the "I"ndexes (keys) of the elements, "for Of" yields the "O"bjects (the elements themselves) ... playing it a bit fast and loose, but you get the idea ;-)

Sharon Gomez

John Peters

I only use map, reduce and foreach.

Josh Ellis

I havenβt heard of that as a way to convert to numbers. Iβll have to give it a shot when Iβm at a computer later!