JavaScript: Iterators and Generators (Part-1)💡📌
Tags: javascript, programming, webdev, advancejavascript
Published: 2024-01-17 02:16:02

In JavaScript, iterating through data set or collections objects such as `arrays` is a very common operation. JavaScript provides a number of ways of iterating over a data-set or collection, from simple `for`loops to `Array.prototype.map()` etc.
ES6 introduces a new mechanism for traversing data: _iteration_. These concepts are central to iteration:
- **Iterable** is a data structure that can be iterated over through iteration.
- **Iterator** is a pointer to the next element in the iteration.
- **Iterability** is an **event** where **_data consumers_** get their data from **Iterable** _**data sources**_ with the help of **Iterator**.
![Interface Iterable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oj3nt57yqk86gvo8also.png)
Practically not possible to create consumers for all data sources, that’s the reason ES6 introduces _Iterable_ interface/protocol.

So Iterators and Generators provide a mechanism for customizing the behavior of control structures or data-consumers such as <u>`for...of`</u> loop in JavaScript to iterate over collections in a simple and readable manner. Built-in JavaScript functions and methods, such as `Array.prototype.map()` or `Array.prototype.forEach()` to process collections internally use Iterators.

In this article we will cover the below concepts :

**1. Iterators.**
**2. Iterators Interface/Protocol.**
**3. Iterables.**
**4. Iterables Interface/Protocol.**
**5. Custom Iterators.**
**6. Custom Iterables.**
**7. Iterators vs Iterables.**

---

## Iterators.

**What is Iterators?**
An Iterator is a structured pattern for pulling information from a source in one-at-a-time fashion. Conceptually, an "iterator" is an object that provides a sequence of values one-at-a-time when requested.

> _Long story short, iterator is a closure which returns an object having function next(), on each subsequent calling of the next function we get the next iteration value_.

![Iterator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uue06q117ybfjwmcuz6h.png)


**Principle of an Iterator**
1. next() : `next` function returns an object consisting of two keys `{value , done}`. 
2. {value , done} : Each `next` execution returns a `value` but `done` is returned as `false` until the _iteration_ is complete(reaches length of the array/ object). Once all the `values` are _iterated_ the `done` is returned as `true` and `value` turns out to be `undefined`.
3. Symbol.iterator: This `[Symbol.iterator]` is a well-known symbol in JavaScript that defines the default _iterator_ for an object. It is typically implemented as a function that returns the _iterator_ object itself.

![Iterator Object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xnxm5jipabyzjvbkbgz.png)

To use an iterator you typically call the `Symbol.iterator` method on a collection or data structure to obtain an iterator object.

![Iterator example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/joaox4tvc573f8p1ogqm.png)

## Iterators Interface/Protocol
The concept of the protocol can be split into two. The _iterable_, the data structure itself, and the _iterator_, a **pointer** that moves over the **iterable**.

The _iterator_ interface or protocol defines an standard to produce a sequence of values. This `protocol` is really an object that contains a **next()** method and this **next()** method returns another object with two properties, **value** and **done**.

![Iterator Protocol](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fkj1jd0h62mg83wycpus.png)

The **next()** method always returns an object with **value** and **done** properties. The **value** property contains the current value of the iteration and the **done** property indicates the termination of the _iterator_.

whenever, any `data-source` implement the `[Symbol.iterator]` protocol that produces an _iterator_ and makes the `data-structure` _iterable_ whenever the data structure in placed in a loop. 

![Iterator Protocol1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt5dt2kc1wwmkhp7gav5.png)

Key points about `Symbol.iterator` :

- value of this is a function.
- when we call the function associated with `Symbol.iterator` , it gives us a `iterator object`.
- **iterator object** returned from `Symbol.iterator` method has `.next` method associated it it.
- And one each `next()` call we get the next value along the `done` status.

![Itr example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k5lmak69wnohn48kddfr.png)

> We have to iterate one extra time, then only we get `done:true`.

**Custom Iterators**
Now, let’s create an custom iterator that returns only the  administrators' names. consider `true` values are admin.
```
const users = {
    james: false,
    andrew: true,
    alexander: false,
    daisy: false,
    luke: false,
    clare: true,
    
    [Symbol.iterator]() {
        const keys = Object.keys(this);
        let index = 0;

        const iterator = {
             // each call will return a new iterator
            next: () => {
                while (!this[keys[index]] && index < keys.length) index++;

                
                // here the relevant part
                return { 
                    done: index >= keys.length,
                    // after reading the name corresponding to the current index,
                    // do not forget to move forward the 'index'
                    // for the next iteration
                    value: keys[index++],
                };
            }
        }

        return iterator;
    }
}

for (let name of users) {
  console.log(name); //"andrew","clare"
}
```

## Iterables.

**What is Iterable?**
In general, it is a `data structure` that allows its data to be consumed. It does so by implementing a method whose key is `Symbol.iterator` which returns an iterator.
> From a technical perspective, an “iterable” isn’t a specific data type in JS. Rather, it’s a protocol that various data types and objects can implement and the JS engine will treat such values as iterables.

**Principle of an Iterable**

- To call any object iterable, it needs to implement the iterable interface.
- The _iterable_ object must have a `@@iterator` method that returns an _iterator_ object. The `@@iterator` key is a symbol that can be accessed via `Symbol.iterator`.
- The property `Symbol.Iterator` on an object converts the object into Iterable.
- Iterables which can iterate only once (such as Generators) customarily return `this` from their @@iterator method.
- Iterables which can be iterated many times must return a new iterator on each invocation of @@iterator.

```
let iterable ={
    [Symbol.iterator] : () => {
        //Iterator defination
    }
}
```
## Iterable Interface/Protocol
**The iterable protocol** allows JavaScript objects to define or customize their iteration behavior. By being an iterable object it needs to implement an `@@iterator` method (an iterator key), meaning that the object (or one of the objects up its `prototype chain`) must have a property with a `@@iterator` key which is available via constant `Symbol.iterator`, this method needs to returns an iterator protocol.

Whenever an object needs to be iterated (such as at the beginning of a <u>`for...of`</u> loop), its `@@iterator` method is called with no arguments, and the returned iterator is used to obtain the values to be iterated.

![Iterable protocol](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohyzbtkaebaziml26dz9.png)

**Custom Iterables.**
We are writing an iterable object with will iterate over an array and print the array values.

```
const iterable = {
  numbers: [1, 2, 3, 4, 5],

  [Symbol.iterator]: function () {
    let index = 0;

    return {
      next: function () {
        if (index < this.numbers.length) {
          let temp = { value: this.numbers[index], done: false };
          index++;
          return temp;
        } else {
          return { value: undefined, done: true };
        }
      }.bind(this),
    };
  },
};

for (let i of iterable) {
  console.log(i); // result is: 1,2,3,4,5
}
```

## Iterators vs Iterables.

- As discussed above Iterable is an object which consists of an Iterator
- Iterator is defined under the key Symbol.Iterator.
- Iterator is the action definition of iteration this holds the custom logic of next() function
- Next function is called iteratively and as per the protocol it returns value and done keys.

we will discuss about **Generators** in upcoming blog **JavaScript: Iterators and Generators (Part-2)**.

_"That's all folks!"_

### References:
Books
_ES6 & Beyond (YDKJS)-kyle simpson_
Images
[Google](https://www.google.com) and designed.