Iteration Protocol in JavaScript-Part 1

Sunilkathuria
In Computing World
Published in
6 min readMay 22, 2024

Look at the code snippets below.

In the first code snippet, the for loop iterates through each character of the through string “username”. In the second code snippet, the for loop iterates every element of an array “numbers”.
This is possible because array and string data types are “iterable.”

In JavaScript, an object becomes iterable when it ‘speaks’ the language of ‘Iteration Protocols.’ These protocols, namely the ‘Iterable protocol’ and ‘Iterator protocol, ‘enable the object to be iterated over.

Consider a situation in which you are writing a JS program to manage your book collection and want to implement a feature that iterates through the collection of books. This demands the implementation of Iteration protocols. In this article, we will learn to implement them.

Iterable Protocol

It is a mechanism for defining or customizing an object’s iteration behavior. This protocol allows using the “for.. of” loop with an object. Array, string, set, and map are built-in datatypes that support this behavior (refer to the code snippet above). However, it is not available for user-defined objects.

[Symbol.iterator] and @@iterator

To implement the iterable protocol in a user-defined object, it must implement a method defined with `[Symbol.iterator]`. This implementation makes an object iterable. The method takes no argument and confirms or follows the iterator protocol.

Note: [Symbol.iterator] is a built-in Symbol in JS.

The official documentation states,

In order to be iterable, an object must implement the @@iterator method…

Whenever an object needs to be iterated (such as at the beginning of a for…of loop), its @@iterator method is called with no arguments…

The @@iterator is an internal representation of [Symbol.iterator]. We define an iterable method using [Symbol.iterator], and JS internally uses @@iterator to identify this method and uses it to iterate over an object.

Iterator protocol

The method defined with [Symbol.iterator] takes no argument and confirms the iterator protocol.
This protocol suggests that the method must return an iterator object.
An object is an iterator object when it defines a method “next()”. This “next()” method manages the iteration process.

next() method

This method is repeatedly called to iterate over the elements. Each call to this method returns an object with two properties.
value: It is the next value in the iteration sequence.
done: A Boolean variable that indicates whether an iteration is complete. false indicates more items in the sequence, and true indicates otherwise.

Note: both properties are optional. When not defined, the value is set to undefined, and done is set to false.

Pseudocode of the function next()

Iterator Object

When an object’s [Symbol.iterator] method returns “this,” it is called an iterable iterator. In this case, the object itself implements the next() method.
When an object’s [Symbol.iterator] method returns a separate iterator object, the iterator object implements the next() method.

The following diagram shows the relation between a user-defined object and its iterator object.

Implementing Iterator protocol

In this implementation, we will create a collection of books using a linked list. The linked list adds a new book (node) at the end of the list. Implementing the iteration protocol will allow iteration through the collection of books.

We will see both flavors of implementation. The first one is an iterable iterator, where both the iterable and iterator protocols are implemented in the same object.
The second one is where the iterable and iterator objects are implemented separately.

Iterable Iterator

The “bookCollection” object implements iterable and iterator protocols in this case. The challenge with this approach is that multiple iterator objects interfere with each other. It is best to have a maximum of one iterator object.

The class Book acts as a node of the linked list. It stores the book, the author’s name, and a reference to the next book.

The object myBookCollection maintains the linked list and provides the functionality of adding a new book.

It implements the method [Symbol.iterator], which returns “this”. Reference to itself. It also initializes an attribute “currentBook”, which keeps track of the last returned value from the next() method.

Implementing the next() method iterates through each entry of the “books” whenever this method is called. When all books are iterated through, the method sets the “done” value to “true” and “value” to “undefined”.

The following code adds a few books to the linked list.

The following “for of” loop iterates through each book in the collection.

Output of the “for of” loop

The following code snippet shows how multiple iterator objects interfere with each other in iterable iterators.

Since the iterable method returns its reference (this of the myBookCollection object), multiple iterator objects refer to the same myBookCollection object.
So, all the iterator objects refer to the same attribute, “myBookCollection.currentBook” to keep track of iterated books.
The next() method will update the attribute “myBookCollection.currentBook”, regardless of the iterator object used, and return the next book available in the linked list.

The output of the above “console.log” statements

Iteration protocol

In this example, we will continue to maintain a book collection. The difference here is the book collection object returns a separate iterator object. Each iterator object maintains its variable to keep track of iterated books; these do not interfere with each other. Refer to the following code snippet.

The class Book acts as a node of the linked list. It stores the book, the author’s name, and a reference to the next book.

The object myBookCollection maintains the linked list and provides the functionality of adding a new book.

It implements the method [Symbol.iterator], which returns an iterator object. When creating this new iterator object, it passes the reference of the “books” linked list to it.

The “bookCollectioIterator” class implements the iterator protocol. The next() method implemented in the class iterates through each book whenever this method is called. And just like the previous implementation, when all the books are iterated through, this method sets the “done” value to “true” and “value” to “undefined”.

Note: the variable currentBook is maintained for easy understanding of the concept.

The following code adds a few books to the linked list.

Output of the “for of” loop
The output of the above “console.log” statements

Summary

In this article, we learned…

  • The concept of “Iteration protocols,” which are “iterable protocol” and iterator protocol”.
  • Understood how iterable iterator implementation differs from the objects that implement a separate iterator object.
  • Implemented an example of iterating through a collection of books using “iteration protocols.”

References

GitHub — Source Code

Coming up…

In the next article, we will learn about the generator and how they fit with iteration.

Did you enjoy this article? Please clap it and share it with your friends.
If you have found this article helpful, please subscribe to read more articles.
Feel free to comment!!

--

--