Going Over Iterators … of Javascript

Arseniy Tomkevich
Sep 4, 2018 · 6 min read

ES6 makes a big push to improve Iterators and for a good reason. Iterating over a set of values, where you are either transforming, or using or saving it in some way is a damn big deal, everyone does it and should know how to do it better; its 50% of the job.

So I am glad the new ECMAScript specification makes traversing over Javascript data structures cleaner and easier.

There are three concepts central to iteration:

  • Iterable is a data structure that makes its elements accessible to the public through iteration.
  • Iterator is a pointer to the next element in the iteration.
  • Iterability is an event where data consumers get their data from Iterable data sources with the help of Iterator.

In order to standardize Iterability, so every data consumer could access every data source, ES6 introduced the Iterable interface.

But given that Javascript does not have interfaces, Iterable is more of a convention. Most people call it the Iterable Protocol. It’s really just a way to create an Iterable Data Source by adding a “special” function to an object.

Iterable data sources

A few built-in classes that implement the iterable protocol include Array, String, Map, Set and NodeList.

Those unfamiliar with Map & Set should read about them in my prior article:

String

To loop through a data source we’ll use for… of loop. Here is how I’d loop through every letter in a string.

console output:
I r è n e J o l i o t — C u r i e

But string is a primitive value, how can it be iterable? Well, Iterable doesn’t have to be Array or object. As long as it can be reimagined as a stream, which gets coerced to objects before the iterability takes place.

Array

Looping through Array is just as easy. The best part is that code for the most part is identical to looping through a String.

console output:
I r è n e J o l i o t — C u r i e

Map

Looping through a Map is a little different, since a Map is iterated over its entries. The entries are iterated in the same order in which they were added to the map.

console output:
Irène

Set

Looping through the Set is similar to Map. The entries iterated over in the same order in which they were added to the Set.

console output:
Irène

NodeList

Looping through NodeList

Custom Iterable Objects

Making a custom iterable data source is simple. Just add a custom function with a custom name coming from Symbol.iterator, like so:

object[Symbol.iterator] = function ()

That function must return an object with a function next() which returns an object with 2 properties value & done.

Here is an example, where I create a custom String object. I am not using ES6 to create a class in this case since I need to implement a private variable.

  1. The MyString class has a method [Symbol.iterator], which returns another object with next() method in it.
  2. The next() method will return an object with value and done properties.
  3. The for…of Iterability finishes when next() returns an object with done equals true.

Iterable computed data

Not every object needs to implement the Iterable protocol.

For example, all the Javascript Iterable structures (Array, String, Map & Set) have three methods that return iterable objects.

  • entries() returns an Iterable Array with every entry as an array with [key, value] pairs
  • keys() returns an Iterable of keys
  • values() returns an Iterable of values

In order for you to make an object iterable, all that needs to happen is you transform that object into another Iterable structure.

Iterating Language Constructs

These language constructs were designed to iterate over Iterables

Destructuring pattern

This one is pretty useful when you are sure of the variables that would make it into the newly made variables.

console output:
item1 [“Egg Roll”, 1.2]
item2 [“French Fries”, 1.95]
itemB [“Egg Roll”, 1.2]

for-of

The for-of is a new loop that replaces for-in and forEach() and supports the new iteration protocol.

Array.from

This construct converts an “iterable” data source into an Array. Here is an example of converting a String.

Spread operator

Helps us create an Array from any Iterable data source, or insert those values into an array.

console output:
* insertion [“a”, “g”, “h”, “d”, 12, 5, 8]
* copy [12, 5, 8]

Sets & Maps Constructors

Both of the data set constructors support an iterable object as input. For Map every element in iterable must be an array with two elements, a key-value pair.

The Set will add all of iterable object’s elements to the new Set.

Implementing tool functions

Array.from is a good example of a built in tool function. Usually, you’d make a tool function for an object that doesn’t support the iterable protocol for a particular object. The tool function must return an Iterable.

The following tool function converts an object into an Iterable and iterates over its values.

console output:
[true, false, true]

Using Generators instead

Most people find it easier to create a Generator instead of making an Iterable via the protocol. I’ve dedicated an entire section on how to create Generators in my prior article:

Combinators

Combinators are similar to tool functions, but instead of turning one data source into an Iterable, they focus on iterating multiple data sources or iterating only over part of a data source.

Conclusion

Javascript has evolved considerably making the day to day development easier with new language constructs. We no longer have to rely on other libraries to re-construct or iterate over our data.


Arseniy Tomkevich

Written by

I have no special talents. I am only passionately curious for Computer Science, Visual Arts & Cybernetics. linkedin.com/in/atomkevi

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade