How I learned to Stop Looping and Love the Iterator
Tags: javascript, es6, iterables, iterators
Published: 2018-05-30 06:37:14

---
title: How I learned to Stop Looping and Love the Iterator
published: true
description: Deep dive into javascript iterators and iterables
tags: javascript, es6, iterables, iterators
---

Let us all take out a minute from our busy lives to look at past and think how many hours did we waste fixing that `for loop`. If your memory returns an empty array have a look at this one. _*(**Spoiler alert!**, it sums the two consecutive elements of an array and for the first element it pairs it with the last element.)*_


```javascript
 for (var i = 0, len = grid.length, j = len - 1, p1, p2; i < len; j = i++) {
    p1 = grid[i];
    p2 = grid[j];
    sum += p1 + p2;
}
```

## The Problem with `for loop`

The biggest problem, in my opinion, is that they are too powerful. You can easily end up with a wrong `for loop` configuration which might deceivingly work, only to explode later in your production stack. 

> In short, the surface area of `for loop` is so wide that it is a bug magnet. 

## Functional Alternatives

90% of the times you can always convert that good old `for loop` into a nice good looking `.map`/`.reduce`. There are a very few places where things could go wrong with this approach.

```javascript
for (var i = 0; i < array.length; i++) {
    array[i] = array[i] * 2;
}

array = array.map(o => o * 2);
```


## The Iterable Approach

A functional alternative should be your first choice in getting rid of `for loop`s, but there are times when you want to stick to it:

1. You feel performance is critical. For loop is still fastest but only by a very small margin.
2. You want to `break;/continue;` out of loop easily. 
3. Certain complicated objects (`Sets`, `Map`, `NodeList`) don't really have a straightforward way of looping through them.

The smart ECMAScript folks knew about these limitations and probably many more, so they came up with an iteration protocol in ES2015.

### What is a protocol anyway?

Javascript doesn’t have formal protocols like other languages. Think of it as a convention, like how node programmers like to follow error first callback.

## Introducing iterables

Iterables are everywhere in javascript, you have been using them unknowingly. Anything which has a `Symbol.iterator` property is iterable. 

Let us look at the simplest iterable, a string!
```javascript

str = 'hello world';
iterator = str[Symbol.iterator](); // StringIterator {}
iterator.next(); // gives `h`
...
...
iterator.next(); // gives `d`
iterator.next(); // gives `undefined` as no more string left.
```

string type in javascript comes baked in with iteration protocol, which means we can now say strings are iterable.

### What is Symbol and Symbol.iterator?

This topic is worthy of an article itself, but in short `Symbol` solves the problem of sneaking in a property into an object which you do not want to clash with any existing property. Visit [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) for more info 

> So no more putting `@@@@@_my_hidden_property_` in your objects!

`Symbol.iterator` is a globally available constant for anyone to use and implement the iteration protocol. So you can use it to make your own object implement iteration. 

## How do I implement the iteration protocol for my custom objects?

```javascript
class Rand {
  [Symbol.iterator] () {
    let count = 0;
    return {
      next: () => ({ 
        value: count++, 
        done: count > 5
      })
    };
  }
}
var rand = new Rand();
var iterator = rand[Symbol.iterator]();
iterator.next();// {value: 0, done: false}
iterator.next();// {value: 1, done: false}
// .. 
iterator.next();// {value: 5, done: false}
iterator.next();// {value: undefined, done: true}
```
Don't let the syntax bog you down. Let us break this example down:
- `[Symbol.iterator] ()` This weird looking syntax is nothing but a new ES2015 way of initializing properties dynamically. _*(Look [here](https://babeljs.io/docs/plugins/transform-es2015-computed-properties/) more information.)*_
- The `Symbol.iterator` method must return an object `{ next }` _*(Don't forget this is all a convention/protocol)*_. We call this object `iterator`. (More on this in the next section)
- The `.next()` is simply incrementing the count every time it is called and it toggles `done` to `true` when the `count` exceeds `5`.

### What is the difference between `iterable` & `iterator` ?

Repeat after me,
* **Iterable** is an object which implements the iteration protocol.  `string`, `Array`, `Set`, `Map` are all iterables!
```javascript
class Rand {
  [Symbol.iterator] () { // Rand has `Symbol.iterator` method, hence it is an iterable!
    let count = 0;
    return { // The return value is called an `iterator`
      next: () => ({ 
        value: count++, 
        done: count > 5
      })
    };
  }
}
```

* **Iterator** is the thing which is returned by `[Symbol.iterator]()` of an iterable. 
    - It contains useful state information about where the current iteration is and what value to provide next. 
    - Any iterator must have a `.next` method on it (remember this is all a convention?), which would be used to get the next value out of it. 
    - The object returned by the `.next()` method must be `{value, done}`, where `value` is the current value and `done` tells whether iteration has finished or not.

```javascript
var iterator = rand[Symbol.iterator](); // I am an iterator

iterator.next(); //  {value: 0, done: false}
iterator.next(); //  {value: 1, done: false}
...
iterator.next(); //  {value: 4, done: false}
iterator.next(); //  {value: undefined, done: true}
```

## What do I get out of this complicated protocol?

You get a lot of superpowers for free if you enable iteration in your custom object or use any of Javascript's inbuilt iterables like `Array`, `string`, `Map` or `Set`. 

**1. Super Power: Spread it**

Remember the class `Rand` that we just defined above? Since it is an iterable it inherits the spreading super powers. Visit [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) for more info on spread.
```javascript
var rand = new Rand();
var myArray = [...rand]; // [0, 1, 2, 3, 4] 

// string can also be used since it is an iterable
[..."kushan"]; // ["k", "u", "s", "h", "a", "n"]
```
_*Note: We didn't do `[...rand[Symbol.iterator]()]`, since `...` expects an `iterable` and not `iterator`.*_

**2. Super Power: Use Array.from**
```javascript
Array.from(rand); // [0, 1, 2, 3, 4]
Array.from("kushan"); // ["k", "u", "s", "h", "a", "n"]
```

**3. Super Power: for of loop**

`for of` is a new looping mechanism introduced in ES2015, which only understands iterables. It automagically calls `Symbol.iterator`, stores the iterator behind the scenes and calls `.next` for you. It also stops when the iterator returns `{done:true}`.
  
```javascript
for(const v of rand) {
  console.log(v); 
}
/*Output*/
// 0
// 1 
// ..
// 4
```

> Unlike `spread operator`, `for of` loop can accept both `iterable` or `iterator`.

```javascript
var map = new Map([['a', 1], ['b', 2]]); 

map[Symbol.iterator];// map is iterable because it has the `Symbol.iterator` key 

// `for of` loop understands `iterable`
for (const [key, val] of map) { 
    console.log(key, val); // 'a', 1
}

// `for of` loop also understands iterators
var iterator = map[Symbol.iterator](); // returns an iterator
for (const [key, val] of iterator) {
    console.log(key, val); // 'a', 1
}

// .keys() is a part of `Map` api
var keyIterator = map.keys();   // returns an iterator
for (const key of keyIterator) {
    console.log(key); // 'a'
}
// .values() is a part of `Map` api
var valueIterator = map.values();   // returns an iterator
for (const val of valueIterator) {
     console.log(val); // 1'
}
```


**4. Super Power: Destructuring**

This is one of my favourite for demoing super powers of `iterables`. ES2015 introduced [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), which is built on top of iterables. You can only destruct iterables!

```javascript
// array is iterable
[a, b] = [10, 20]; // a=10, b=20

// our custom class rand is Destructable :P
[a, b, c] = rand; // a = 0, b = 1, c = 2

// you can do fancy things like
[a, ...b] = rand; // a = 0, b = [1, 2, 3, 4]

```


## Summary

Please share any other super power that you get for free when using `iterables`. I hope this article helped you understand `iterables` & `iterators`.

Don't forget to check out my previous articles.

- [Javascript WeakMap](https://dev.to/kepta/javascript-underdogs-part-1---the-weakmap-4jih) 
- [9 promising promise tips](https://dev.to/kepta/promising-promise-tips--c8f)

If you ❤️ this article, please share this article to spread the words.