Iterator Pattern
Learn how to implement the Iterator protocol.
We'll cover the following
The Iterator pattern is a fundamental pattern and it’s so important and commonly used that it’s usually built into the programming language itself. All major programming languages implement the pattern in one way or another, including, of course, JavaScript (starting from the ECMAScript2015 specification).
The Iterator pattern defines a common interface or protocol for iterating the elements of a container, such as an array or a tree data structure. Usually, the algorithm for iterating over the elements of a container is different depending on the actual structure of the data. Think about iterating over an array vs. traversing a tree: in the first situation, we need just a simple loop; in the second, a more complex tree traversal algorithm is required. With the Iterator pattern, we hide the details about the algorithm being used or the structure of the data and provide a common interface for iterating over any type of container. In essence, the Iterator pattern allows us to decouple the implementation of the traversal algorithm from the way we consume the results (the elements) of the traversal operation.
In JavaScript, however, iterators work great even with other types of constructs, which are not necessarily containers, such as event emitters and streams. Therefore, we can say in more general terms that the Iterator pattern defines an interface to iterate over elements produced or retrieved in sequence.
The iterator protocol
In JavaScript, the Iterator pattern is implemented through protocols rather than through formal constructs, such as inheritance. This essentially means that the interaction between the implementer and the consumer of the Iterator pattern is communicated using interfaces and objects whose shape is agreed in advance.
The starting point for implementing the Iterator pattern in JavaScript is the iterator protocol, which defines an interface for producing a sequence of values. So, an iterator is an object implementing a next()
method having the following behavior: each time the method is called, the function returns the next element in the iteration through an object, called the iterator result, having two properties—done
and value
.
done
is set totrue
when the iteration is complete, or in other words, when there are no more elements to return. Otherwise,done
isundefined
orfalse
.value
contains the current element of the iteration and it can be left undefined if done is true. Ifvalue
is set even whendone
istrue
, then it’s said thatvalue
contains the return value of the iteration, a value which is not part of the elements being iterated, but it’s related to the iteration itself as a whole (for example, the time spent iterating all the elements or the average of all the elements iterated if the elements are numbers).
Note: Nothing prevents us from adding extra properties to the object returned by an iterator. However, those properties will be simply ignored by the built-in constructs or APIs consuming the iterator.
Example
Let’s use a quick example to demonstrate how to implement the iterator protocol. Let’s implement a createAlphabetIterator()
named factory function, which creates an iterator that allows us to traverse all the letters of the English alphabet. Such a function would look like this:
Get hands-on with 1400+ tech skills courses.