Using iterators in JavaScript

tl;dr: Iterators are a relatively unknown feature of JavaScript. They are used to make the properties of objects iterable. This can be used, for example, to write a range function, that returns all numbers in a given interval.

In fact, there are some practical applications, although admittedly not too many. One of these applications is based on one of the symbols that are already fixed in the language: We are talking about the well-known symbols. Among these symbols is the Symbol.iterator symbol, which can be used to design objects that can be looped through.

In JavaScript, any object containing a function whose name corresponds to Symbol.iterator can be iterated. The basic structure therefore looks as follows:

const iterable = {
  [Symbol.iterator] () {
    // ...
  }
};

This function must return an object containing a next function. The next function may already be known from generator functions: It returns an object with two properties, value and done. The first property specifies the value of the current iteration, while the second property specifies whether further values are available.

This way, for example, it is easy to build an object that can be used to list the numbers from 1 to 10:

const iterable = {
  [Symbol.iterator] () {    
    return {
      currentValue: 1,

      next () {
        const result = {
          value: this.currentValue,
          done: this.currentValue > 10
        };

        this.currentValue += 1;

        return result;
      }
    };
  }
};

The easiest way to iterate the object is to use a for of loop:

for (const number of iterable) {
  console.log(number);
}
// => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Alternatively, you can use the from method of the Array class to convert the numbers created by the object into an array:

const numbers = Array.from(iterable);
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

All this suggests writing a range function that creates a corresponding object that lists all values within a certain interval:

const range = function (min, max) {
  return {
    [Symbol.iterator] () {    
      return {
        currentValue: min,

        next () {
          const result = {
            value: this.currentValue,
            done: this.currentValue > max
          };

          this.currentValue += 1;

          return result;
        }
      };
    }
  };
};

Of course, you can easily add more features to this function. It is conceivable, for example, to be able to generate descending intervals or to use step sizes other than one.

The npm module bereich works in exactly this way (bereich is the German word for range). So if you are ever again in a situation where you have to create a range of numbers, you can use this module to do just that.

Twitter Facebook LinkedIn

Golo Roden

Founder, CTO, and managing partner

Since we want to deliver elegant yet simple solutions of high quality for complex problems, we care about details with love: things are done when they are done, and we give them the time they need to mature.