# What the Heck Are Iterators and Generators in JavaScript

Have you ever come across syntax like `function*` or statements such as `it.next()` and didn't have a clue what these are, where they come from and what they can be used for?

You've come to the right place! Recently I needed to revisit iterators and generators in JavaScript. Here's a simple introduction to what these are and what are their applications.

## Iterator

Let's first look at what iterator is from a syntax perspective. Simply put, an iterator is a JavaScript object that implements a zero-argument `next` method which returns an object with at least two properties - `done` and `value`. It's called the [Iterator Protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol).

Let's look at a simple example of an iterator.

```JavaScript
const iterator = {
    next() {
        return {
            value: "Hello, I'm an iterator",
            done: true,
        };
    },
};
``` 

Nothing crazy. As you might expect, having defined this, we can do the following.

```JavaScript
const result = iterator.next();
console.log(result.value);
console.log(result.done);
``` 

```Console
Hello, I'm an iterator
true
```

And that's an iterator. Now we know what it is, let's look at what it can be used for. [Documentation on Iterators and Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) mentions the following.

> In JavaScript an iterator is an object which defines a sequence and potentially a return value upon its termination.

Instead of having an iterator that always returns the same value, let's make an iterator that will allow iterating over a sequence of words. How about `Hello World` for a starter?

```JavaScript
const words = ["Hello", "World"];
let index = 0;

const iterator = {
    next() {
        return {
            value: words[index++],
            done: index === words.length + 1,
        };
    },
};
```

We can run this in a similar way.

```JavaScript
let result = iterator.next();
console.log(result.value, result.done);

result = iterator.next();
console.log(result.value, result.done);

result = iterator.next();
console.log(result.value, result.done);
```

```Console
Hello false
World false
undefined true
```

Cool, but this is overly imperative, this could have been done with a simple loop with less code. What can be done about this then? To understand this, we need to look at another construct that builds on top of an iterator - [Iterable Protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol).

## Iterable

Iterable is an object which can specify a custom looping behaviour by exposing a method under a special `Symbol.iterator` key which returns an iterator. And guess what uses the Iterable protocol? Loops - `for .. of` loop in particular.

```JavaScript
const words = ["Hello", "World"];
let index = 0;

const iterator = {
    next() {
        return {
            value: words[index++],
            done: index === words.length + 1,
        };
    },
};

const iterable = {
    [Symbol.iterator]() {
        return iterator;
    },
};
```

Having this defined we can do the following.

```JavaScript
for (let word of iterable) {
    console.log(word);
}
```

```Console
Hello
World
```

This is an example of an iterable defining the sequence of values and the `for .. of` loop being the algorithm that iterates over these values. But you can think about implementing your own mechanism that based on these protocols will allow iterating in more intricate ways, depending on the requirements that you might have.

## Generators

When you look closely at Iterator and Iterable protocols you can spot that these are not mutually exclusive. An object could technically satisfy both! It might look something like this.

```JavaScript
const iteratorAndIterable = {
    next() {
        // ...
    },
    [Symbol.iterator]() {
        return this;
    },
};
```

There's a name for such an object - a [generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator). On its own, it might not be really useful. What is important to know, though, is that it is returned from a [generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) - function declared with `function*` syntax. This type of function allows us to define a sequence in a different, somewhat streamlined way, using the `yield` keyword. Let's extend our `Hello World` example, adding a user name at the end. Instead of defining an iterable, let's use a generator function.

```JavaScript
function* generateHelloWorld(name) {
    yield "Hello";
    yield "World";
    yield name;
}
```

What this returns is a generator. It will return whatever the function yields to on each subsequent call of its `next` function. But you already know that we don't have to call `next` manually, we can simply pass such generator to a `for .. of` loop (since a generator is an iterable, as mentioned before). Let's do this!

```JavaScript
const generator = generateHelloWorld("Tomasz");

for (let word of generator) {
    console.log(word);
}
```

```Console
Hello
World
Tomasz
```

Awesome! We achieved even more flexibility with less code.

## Conclusion

That's it! Iterators and iterables provide interfaces we can use to define sequences or values. These sequences can be processed by custom algorithms or by inbuilt JavaScript constructs such as `for .. of` loop. The generator function provides an easy way to create iterators.

I hope this allows you to grasp what iterators and generators are and what they can be useful for!

### Further reading and references

- Full code available in this [Gist](https://gist.github.com/tomaszgil/772d262f2b0485214391d1b97e87483f)
- Documentation on [Generators and Iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) on [MDN](https://developer.mozilla.org/en-US/)
- Photo by [Fernando Reyes](https://unsplash.com/@nundo) on [Unsplash](https://unsplash.com/photos/__WsQ9lCZgo)
