In some scenarios, you may find yourself creating a class which has items which need to be iterated over. This might be a linked list, a binary tree, a multi-set, or something else which holds a collection of items in one sense or another. In these cases, it can be very useful to implement the iterable protocol to allow for native for..of iteration over your class. This type of approach would allow you to use native JavaScript functionality for a clean code implementation. In the sections below, we'll introduce the concepts, discuss how JavaScript has built-in support for iterables, outline how to implement this functionality, and use a few examples to show it in action.
For...Of Loops
A for of loop is a loop construct which will allow you to loop over any object that is iterable. JavaScript iterables are object, such as Arrays, which conform to the iterable protocol, which will introduce in more detail in the sections below. This conformity gives the JavaScript engine what it needs to allow for native iteration using for..of loops. The formal specification of the syntax for a for..of loop:
The syntax is very similar to what we see in a for loop. We declare a variable with let, const, or var and the loop will iterate over each item in array, or other iterable type, we specify. Generally, const will be the most appropriate choice, as there should be no reason to override the variable reference specified within the loop. The example below shows how we can use this for an array:
In the next section, we will introduce the iterable protocol and outline how to use it with classes to allow use of for..of over them.
Iterable Protocol
The iterable protocol is a JavaScript language feature which allows JavaScript objects to define their iteration behavior in a standarized manner. This can be applied to classes, prototypes, plain objects, and used as their own functions. In this article, we will focus on implementing this for classes. To allow a class to be iterable, and thus allow it to be used in for..of loops, it will need to implement a function defined as [Symbol.iterator]()
. This is similar in concept to a class implementing an interface. The code below shows an example of a custom iterable class which allows for iteration over an array:
Notice in the code above, we are returning an object with a function next, which in turn returns properties value and done. This is the type of object which must be returned by this protocol. However, in the sections below, we'll outline a simpler way of declaring iterables so you do not need to do this.
Iterables with Generators
If we implement an iterable with a generator function, we will not need to handle returning a next function as described above. JavaScript will use a generator function to handle that for us behind the scenes. The implementation itself will also look cleaner and more concise. If you are not familiar with JavaScript generator functions, feel free to visit our introduction to generator functions. The example below is a rewrite of the example above using a generator function. Notice the "*" asterisk which prefixes the [Symbol.iterator]()
declaration; this is how we specify that it will be a generator function:
This time, instead of returning an object which has a function which returns another object, we can simply yield values as we move through them. This is one of the simplest approaches, and is the approach we will take in the rest of this article. In the sections below, we'll implement a few more iterables with some different types of examples:
Example: Iterate over Words in a String
In this example, we'll create an iterable class which will take a string and allow the consumer to iterate over a word at a time. We'll define a word as a sequence of characters with no spaces; we will not check if they are actual valid words:
Example: Perform a Breadth First Search
In this example, we will accept a binary tree's root node in the constructor, then have our iterable perform a breadth-first search and yield each node value along the way. For a brief introduction to binary trees, please visit our introduction to binary trees dev page.