Writing Iterator and Generator using JavaScript

off.tokyo
4 min readMay 1, 2021

source : Writing Iterator and Generator using JavaScript | off.tokyo

Iteration is the foundation of programming. The degree to which a programming language helps you iterate makes a big difference in your programming comfort.

JavaScript has been a lagging language when it comes to iteration. However, with the introduction of Iterator and Generator, this is about to change.

Iterator

Itreable and Iterator

In JavaScript, an object that can be iterated over is called an iterable, and typical examples of iterables are Arrays and Maps. A typical example of an Iterable is an Array or Map, which is iterable because it has multiple values.

An Iterable object has an Iterator, which can be obtained with IterableSymbol.iterator.

const array = [1, 2, 3];
const iterator = array[Symbol.iterator]();

Iterator has only one method, next(), which can be used to retrieve the next value in an Iterable.

const array = [1, 2, 3];
const iterator = array[Symbol.iterator]();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3

The value obtained by next() is an object that is {value: the next value, done: whether it has finished or not}.

By checking the value of value, we can get the value of Iterable.

By checking the value of value, we can get the value of the Iterable, and by checking the value of done, we can get the value of the bool to see if the iteration has finished or not.

In other words, the above code can be rewritten using a loop as follows

const array = [1, 2, 3];
const iterator = array[Symbol.iterator]();
let next = iterator.next();
while(!next.done) {
console.log(next.value); // 1 2 3
next = iterator.next();
}

Iterator is a smart way to write iterations.

However, this is still cumbersome. Therefore, javaScript provides a simpler way to write Iterator iteration.

The for-of statement

The for-of statement is the easiest way to handle an Iterable.

Rather than explaining it in words, it will be easier to understand if you look at the code first.

const array = [1, 2, 3];for(const val of array) {
console.log(val); // 1 2 3
}

Creating your own Iterators and Iterables

It is also possible to create your own Iterators and Iterables.

Creating an Iterator is as simple as implementing a next() method that returns {value, done}.

Iterable is also a simple matter of implementing Symbol.iterator.

For example, let’s consider implementing the range() function.

The functions to create an Iterator and an Iterable look like the following

function createRangeIterator(end) {
let currentValue = 0;
const iterator = new Object();
iterator.next = () => {
const value = currentValue++;
const done = currentValue > end;
const result = done ? {done: done} : {value: value, done: done};
return result;
};

return iterator;
}
function range(end) {
const iterable = new Object();
iterable[Symbol.iterator] = () => createRangeIterator(end);

return iterable;
}
for(const val of range(3)) {
console.log(val); // 0 1 2
}

Since the Iterator mechanism is simple, it is easy to create your own.

Generator

Generator function and yield return

Even though the Iterator mechanism itself is simple, the actual implementation is quite lengthy. Of course, there are excellent programmers who can read and write this code easily, but it is difficult for most people to do so.

The Generator provides a very easy way to work with Iterators and Iterables, allowing you to automatically iterate over them with simple code.

To use the Generator, use function* instead of function, and yield instead of return. To use Generator, use function* instead of function,

and yield instead of return. This is all you need to complete the Generator. Here, the function defined by function* is called the Generator function.

function* generator() {
yield 1;
yield 2;
yield 3;
}
for(const val of generator()) {
console.log(val); // 1 2 3
}

The Generator function returns a Generator object.

The Generator object is an Iterable and an Iterator object.

The generator object is both an Iterator and an Iterator object, and can be used as an Iterator, such as generator.next().value, or as an Iterable, such as using for-of to retrieve a value.

When next() is called, the Generator function will stop and return the yielded value each time it is yielded.

When next() is called again, it resumes function execution and proceeds to the next yield.

The Generator behaves like an Iterator by repeating this process.

yield* to yield an Iterable

You can also use yield* instead of yield to automatically yield the contents of an Iterable one by one.

function* generator() {
yield* [1, 2, 3];
}
for(const val of generator()) {
console.log(val); // 1 2 3
}

Saving the Context

yield and yield* preserve the context of the function. This means that the values of variables in the function will be preserved. As a concrete example, you can write a generator like the following

function* generator() {
for(let i=0; i< 3; i++) {
yield i;
}
}
for(const val of generator()) {
console.log(val); // 0 1 2
}

By using this, for example, the previous range function can be easily written as follows

function* range(end) {
for(let i=0; i < end; i++) {
yield i;
}
}
for(const val of range(3)) {
console.log(val); // 0 1 2
}

I was able to write it much more easily.

Summary

  • Iterable objects are Iterable
  • Iterable objects have an Iterator.
  • Iterable can be easily iterated by using for-of statement
  • Iterator and Iterable can be created by oneself.
  • Iterables can be easily created using the Generator.
  • Generator is both an Iterable and an Iterator
  • Generator is both an Iterable and an Iterator ・Yield can be used to return the next value
  • The generator is an Iterable and an Iterator.
  • The context is preserved even if the function is temporarily exited by yield.

*This article is a summary of the Japanese article with only the main points explained in an easy-to-understand manner.

https://sbfl.net/blog/2016/08/17/javascript-iterator-generator/

--

--