Symbol.iterator for modular iteration without cloning or modifying in-place
Tags: javascript, es6, frontend, webdev
Published: 2019-04-11 00:50:07

---
title: Symbol.iterator for modular iteration without cloning or modifying in-place
published: true
description: Iterate forwards, backwards, randomly, infinitely, pairwise, and more with Symbol.iterator
tags: JavaScript, ES6, Frontend, Webdev
---

[`Symbol.iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) is _the_ protocol that makes native objects like `Array`, `Set`, and `Map` iterable. It provides a hook into language features like the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) and [`for…of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) loops.

With `Symbol.iterator`, developers can **redefine navigation patterns without cloning or modifying an object in-place**. That means iterating [forwards, backwards, randomly, infinitely, pairwise](https://medium.com/front-end-weekly/thank-u-symbol-iterator-next-aef9f09ff78), or just about any way you can imagine.

The protocol specification is very simple:

* **Iterable**: the object with a function whose key is `Symbol.iterator`
* **Iterator**: the iterable function, used to obtain the values to be iterated

{% gist https://gist.github.com/Tombarr/4f11ea22ab7f6d31ecb96c762adfec4d %}

These two properties tell the Javascript runtime what the next __value__ is and when iteration is __done__.

Consider this example for iterating in reverse:

{% gist https://gist.github.com/Tombarr/1033a3318d1ad9f955d8532623fd7e0a %}

Instead of iterating backwards using indices or [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse), we have defined the “going backwards” behavior for any array. We have done so while preserving the order and without creating a clone of the original array.

`reverse` can now be used in `for...of` loops or with the spread operator:

{% gist https://gist.github.com/Tombarr/34419c371a165a8105dbf0cd6ea70bbc %}


`Symbol.iterator` can also be used to recreate Python's `range` function.

{% gist https://gist.github.com/Tombarr/ccb0370e7b5078530a9ebf617ecd4345 %}

Now we can elegantly iterate over a range of numbers **without needing to create an intermediate array**.

{% gist https://gist.github.com/Tombarr/c830cc1a66cdd8f7af5de138e63d8d57 %}

It even seems that [performance is comparable to a standard for loop](https://jsperf.com/for-vs-range).

We do not even need to limit ourselves to a single collection. Like many libraries, we can write a `zip` function that combines multiple sequential collections of equal length, _without needing to clone them in their entirety_.

{% gist https://gist.github.com/Tombarr/596dc7567b71aa1a55c2f2d53fb93f09 %}

This allows us to seamlessly iterate pairwise (or triplet-wise):

{% gist https://gist.github.com/Tombarr/77b77a511d20e3e7d7aeb54c66cd33c2 %}

In this case, [`Symbol.iterator` significantly outperforms](https://jsperf.com/js-zip) an cloning implementation using `Array.map`.

There are [many uses for `Symbol.iterator`](https://medium.com/front-end-weekly/thank-u-symbol-iterator-next-aef9f09ff78), and while it is more verbose than `Array.map`, it is more versatile and potentially more efficient.