What you may not know about loops in JS - part 2 - for/of , for/in
Tags: javascript, programming, tutorial
Published: 2021-07-08 15:49:07

In the last post [part 1 - for loop](https://dev.to/ms_74/what-you-may-not-know-about-loops-in-js-part-1-for-loop-4b7j), I described how *for* loop works and shared some common and rare examples of it. 

Now let's look into the other types of loop: `for/of` and `for/in` loops. 

## for/of

The *for/of* loop is fairly new defined by ES6 and is completely different from *for* loop. 

This loop can be used for *iterable* objects (eg. arrays, strings, sets and maps). Let's go through each of the types. 

### with arrays

```
let numbers = [1, 2, 3, 4], sum = 0;
for(let el of numbers) {
    sum += el;
}
sum       // => 10
```
In the above code, the loop iterates through each element of the `numbers` array. Different from the *initialize* expression of the *for* loop, here you can see that the variable `el` is assigned with the the next element of the `numbers` array, before each loop execution.

Using this concept let's create another *infinite* loop 🤓. 
```
let numbers = [1, 2, 3, 4], sum = 0;
for(let el of numbers) {
    sum += el;
    numbers.push(sum);
}
console.log(sum);
// => iteration can never reach the end of the element, and loops infinitely. 
```
![never ending gif](https://media.giphy.com/media/GB3XCL0cnIUxi/giphy.gif)
### with objects

Wait a second, but objects are not iterable. Yes, you are right and if you attempt to loop on an object , the following error will be thrown.`TypeError because o is not iterable`. 

You can loop through objects with `for/of` loop using either of these methods, `Object.keys()`, `Object.values()`or `Object.entries()`. These are iterable because they return an array of properties.
```
//Object.keys returns an array of property names
let o = { x: 1, y: 2, z: 3 };
let keys = "";
for(let k of Object.keys(o)) {
    keys += k;
}
keys  // => "xyz"

//Object.values returns an array of property values.
let sum = 0;
for(let v of Object.values(o)) {
    sum += v;
}
sum // => 6

//Object.entries returns an array of keys and values.
let pairs = "";
for(let [k, v] of Object.entries(o)) {
    pairs += k + v;
}
pairs  // => "x1y2z3"
```

### with strings

Strings can be iterated character by character.
```
let occurrence = {};
for(let char of "Panama") {
    if (occurrence[char]) {
        occurrence[char]++;
    } else {
        occurrence[char] = 1;
    }
}
occurrence   // => {p: 1, a: 3, n: 1, m: 1}
```
Strings are iterated by by Unicode codepoint, not by UTF-16 character. For example in the below code, even when the string length is 4 ( no. of UTF-16 characters), the loop happens 3 times, i.e by the number of unicode codepoint. 
```
const msg = "❤️🐶";
console.log(msg.length); //outputs => 4
for(let item of msg){
  console.log("wuff"); // logs "wuff" 3 times
}
```
![confused gif](https://media.giphy.com/media/118p3q768COZhu/giphy.gif)

### with set and map

With set, the loop body runs once for each element of the set. 

```
let text = "oh no no no no no way!";
let wordSet = new Set(text.split(" "));
let unique = [];
for(let word of wordSet) {
    unique.push(word);
}
console.log(unique); // => ["oh", "no", "way"]
```

Interestingly with map, it neither iterates the Map keys nor the map values but the key/value pairs i.e each time the iterator returns an array, where the first element is the key and the second element is the respective value. 

```
let m = new Map([[1, "one"]]);
for(let [key, value] of m) {
    key    // => 1
    value  // => "one"
}
```

## for/in

A for/in loop is a lot like for/of loop except that the keyword is *in* instead of *of*. As compared to *for/of* loop, *for/in* loop iterates through any object. 

```
for(let p in o) {      // Assign property names of o to variable p
    console.log(o[p]); // Print the value of each property
}
```

In the above example the variable *p* will hold the property name of the object each time it loops. 

Again the left hand side expression can be any expression than just a variable declaration, like the following example. 

```
let o = { x: 1, y: 2, z: 3 };
let a = [], i = 0;
for(a[i++] in o) /* empty */; //empty body statement 
console.log(a); // => ["x", "y", "z"]
```

Since the left hand expression is evaluated each time during iteration, you can use this behaviour to code like above to copy all the object properties into an array 😎. 

**Note:** 
- The for/in loops over only **enumerable** properties, and it does not enumerate all properties of an object, for eg. property names which are symbols or any built-in methods like toString(). 
But **if you define custom properties or method to an object, they are enumerable by default.** 
Therefore be careful to make them non-enumerable before you use for/in loop for the object. In this case, it is recommended to use for/of with the use of Object.keys() and other Object methods like the examples given for objects in for/loop section.

```
let o = { x: 1 };
o.propertyIsEnumerable("x")  // => true: o has an own enumerable property x
o.propertyIsEnumerable("toString")  // => false: not an own property
Object.prototype.propertyIsEnumerable("toString") // => false: not enumerable
``` 

- **If the body of the loop defines new properties on the object, those properties may or may not be enumerated.** For more info , refer [mdn doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#deleted_added_or_modified_properties).

Hope you got enlightened by these posts and will in future choose wisely between for/in and for/of loop in your code. 

----
Mariam Reba Alexander