Contents

Javascript Iterators

Iterators are a way to process each item of a collection. They were introduced in ES6 and bring the concept of iteration directly into the language.

We are going see what JavaScript iterators are how we can use them to customize the iteration logic.

Iterable objects

The concept of iterable object is fundamental to understand iterators.

An iterable object is an object that defines the behavior for each iteration. In other words an object is iterable if it provides the values that are looped over in a for...of loop.

Example

Let’s say we have a simple array.

1
2
3
4
5
const movies = [
  'The Godfather',
  'Pulp fiction',
  'Fight club'
];

We can iterate over movies with a for...of loop in the following way.

1
2
3
for (const movie of movies) {
    console.log(movie);
}

The loop above logs every movie one by one:

1
2
3
The Godfather
Pulp fiction
Fight club

The example above is possible because Array is a built-in iterable.

Array, TypedArray, String, Map and Set are all built-in iterables. This means that each of them provides a default iteration behavior:

  • Array and TypedArray iterate over their items
  • String iterate over each character
  • Map iterates over its key-value pairs
  • Set iterates over its elements

Non-iterable objects

As we have seen not all objects are iterable by default.
What would happen if we iterated over an non-iterable object?

Let’s say instead of an array we have the following object.

Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const movies = {
    'The Godfather': {
        year: '1972',
        director: 'Francis Ford Coppola'
    },
    'Pulp fiction': {
        year: '1994',
        director: 'Quentin Tarantino'
    }
}

Let’s try to iterate over movies as we did above.

1
2
3
for (const movie of movies) {
    console.log(movie);
}

Now we get a different result:

error:
for (const movie of movies) {
          ^
TypeError: movies is not iterable

The error is pretty explanatory, let’s see how we can turn non-iterable into iterable objects.

Iteration protocols

In order to be able to create iterables, ES6 introduced a couple of iteration protocols:

  • the iterable protocol
  • the iterator protocol

These protocols can be implemented by any object by following some conventions.

The iterable protocol allows us to define the iteration behavior for our objects.

In order to be iterable, an object must implement a function whose key is Symbol.iterator and this function must return an object conforming to the iterator protocol.

The iterator protocol is a standard way to produce a sequence of values and a return value when all values have been generated.

In order to be an iterator, an object must implement a next() that returns an object of the following type:

1
2
3
4
{
    value: any; // the current value
    done: bool; // whether or not the loop reached the last item
}

To recap, if we want our object to be iterable we have to add a function (keyed as Symbol.iterator) that returns an object with a next method that returns an object with the value of the current iteration and its status.

Talk is cheap, show me the code!

This might sound confusing so the best way to understand it is with an example.

Let’s make an iterable object

Let’s use the last version of our movie object and make it iterable. Our goal is also to restructure the iteration value to an object that includes the title of the movie.

Here is how we could do it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
movies[Symbol.iterator] = function() {
    let i = 0;
    const keys = Object.keys(this)

    return {
      next: () => {
          const value = {
              title: keys[i],
              ...movies[keys[i]],
          }

          const done = i >= keys.length

          i++;

          return { value, done }
      }
    }
};

As you can see in the iterator function I make an array of keys which is the list of movie titles [ 'The Godfather', 'Pulp fiction' ] and I use it in combination with an index i that I increase in each iteration to create the desired object for the value.

Now, with this being done, let’s iterate over our object again.

1
2
3
4
5
6
7
for (const movie of movies) {
    console.log(movie);
}

// Here is what you would see in the console:
{ title: 'The Godfather', year: '1972', director: 'Francis Ford Coppola' }
{ title: 'Pulp fiction', year: '1994', director: 'Quentin Tarantino' }

Conclusion

In this tutorial, we have learned about the JavaScript iterators and how to use the iteration protocols to implement customize iteration logic.