Let's loop - for...in vs for...of
Tags: javascript, webdev, productivity, learning
Published: 2019-07-16 11:55:17

---
title: Let's loop - for...in vs for...of
published: true
description: These two alternatives to for loops are wonderful, but they do different things. Let's understand them better!
tags: javascript, webdev, productivity, learning
cover_image: https://thepracticaldev.s3.amazonaws.com/i/az4ycxwlbhfoyuy3qyaj.jpg
canonical_url: https://tenmilesquare.com/lets-loop-for-in-vs-for-of/
---

A bit ago I was working with [Object.entries](https://dev.to/laurieontech/introducing-object-fromentries-1d5l) and wasn't seeing the functionality I expected. I kept staring, and staring and finally realized I was using "for in" instead of "for of".

{% twitter 1146083249107681282 %}


And that got me thinking I should write a post to talk about the differences. So here we are!

# A Primer

`for...in` and `for...of` are substitutions for a traditional for loop. It's quite common to need to do something like this.

```javascript
for (let i = 0; i < arr.length; i++) {
  // do something here
}
```
So the ability to iterate over all kinds of data structures is a nice shortcut.

# For...of

`for...of` is designed for arrays and other iterables. Here's an example.

```javascript
let arr = [1, 2, 3]
for (item of arr) {
  console.log(item)
}
// 1
// 2
// 3
``` 
Keep in mind that a number of things are iterables in JavaScript. This includes arrays, strings, maps, sets, etc.

# For...in

On the other hand, `for...in` can handle objects.

```javascript
let obj = {a:1, b:2, c:3}
for (item in obj) {
  console.log(item)
}
// a
// b
// c
```

What's important to note here is that `item` is actually referencing the key of a given key-value pair. If we want to access the value we can do something like this.

```javascript
let obj = {a:1, b:2, c:3}
for (item in obj) {
  console.log(obj[item])
}
// 1
// 2
// 3
```

# For...in and iterables

As it turns out, `for...in` can handle iterables as well as objects. 

```javascript
let arr = [1, 2, 3]
for (idx in arr) {
  console.log(idx)
}
// 0
// 1
// 2
```

Instead of referencing the key, as it does for objects, it references the index of a given element in the array.

If we want to access the element itself, our code would look like this.

```javascript
let arr = [1, 2, 3]
for (idx in arr) {
  console.log(arr[idx])
}
// 1
// 2
// 3
```

# My wonky example

So it's worth understanding why both versions worked in my example up above and what the difference is. 

We'll start with `for...of`. 

>Note that this example uses [destructuring assignment](https://dev.to/laurieontech/3-powerful-examples-of-destructuring-assignment-jlf) and [Object.entries](https://dev.to/laurieontech/introducing-object-fromentries-1d5l), if you want a refresher on those concepts.

### For...of

```javascript
let obj = {a:1, b:2, c:3}
let newObj = {}
for (let [key, value] of Object.entries(obj)) {
  newObj[key] = value;
}
// newObj is { a: 1, b: 2, c: 3 }
```
It might help to break this down a bit. `Object.entries()` is turning our `obj` into a multidimensional array representation. 

```javascript
[[a,1], [b,2], [c,3]]
```
As we iterate through that array we're looking at each element, which is an array itself. 

From there, we're diving down a level, into that array element, and assigning the name `key` to the first element and `value` to the second.

Finally, we add those key-value pairs to `newObj`. This seems to work as intended. 

So what happens with `for...in`?

### For...in

```javascript
let obj = {a:1, b:2, c:3}
let newObj = {}
for (let [key, value] in Object.entries(obj)) {
  newObj[key] = value;
}
// newObj is { 0: undefined, 1: undefined, 2: undefined }
```

Uhhh, what?! Let's break this down.

> As an aside, now you see why this was not at all the result I was expecting.

So just like before, `Object.entries()` is giving us this.

```javascript
[[a,1], [b,2], [c,3]]
```
However, as we iterate through the array, we're looking at the array index **not** the value. So our first entry is `0`, which has no `[key, value]` to destructure. `key` becomes `0` and `value` is given a value of `undefined`.

### Rabbit hole

Ok, we'll get back to the main point in a second, but I went down a deep rabbit hole trying to understand why this even worked. If we were to break it down to the most basic level, this is the code we're looking at.

```javascript
const [key, value] = 0;
```
And that's not valid! It throws `TypeError: 0 is not iterable`. So why is this the result when using `for...in`?

```javascript
// key is 0
// value is undefined
```

Taken from the [mozilla docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) this is why:
"Array indexes are just enumerable properties with integer names and are otherwise identical to general object properties."

Instead of `0` being of type `number` as it is in our `const` example, it's actually a string!

So our super drilled down example of what is happening inside the `[key, value]` destructuring is really this.

```javascript
let num = 0;
const [key, value] = num.toString();
// key is '0'
// value is undefined
```

### Ok, back to the point

If we are using `for...in` in my example and we want what I was expecting to see, there is a way to get it. 

```javascript
let obj = {a:1, b:2, c:3}
let newObj = {}
for (let idx in Object.entries(obj)){
    const [key, value] = Object.entries(obj)[idx]
    newObj[key] = value
}
// newObj is { a: 1, b: 2, c: 3 }
```
However, it's clear that using `for...of` is the better choice in this case.

# And that's that

It's nice to have so many options, but it's important to pick the right tool for the job. Otherwise, you'll end up with some very unexpected behavior!