[Screencast] Iterables in Javascript

Learn what iterables are and how they are used in Javascript

An Aha! moment, delivered to your inbox every week. Check out the JS Tips & Tricks Newsletter!

Iterables

In the previous post, we’ve covered what iterators are, and how JS defines a protocol for them. We’ve seen that they provide a one-shot traversal over a collection. But they require a lot of boilerplate to make them work.

This post introduces the iterable protocol, which is a standardized way to make iterators.

Iterables

Just like with iterators, making an object to conform to the iterable protocol is just a matter of adding a function. Its name is Symbol.iterator, and it needs to be zero-arity and has to return an iterator. Think of it as a multiple-use factory to make one-shot iterators.

To wrap the iterator from the previous post into an iterable (Try it):

const iterable = {
	[Symbol.iterator]: () => {
		let num = 0;

		return {
			next: () => {
				return num < 3 ? {value: ++num, done: false} : {done: true};
			}
		}
	}
}

Using this iterable, the 1, 2, and 3 elements can be iterated over and over again:

const it1 = iterable[Symbol.iterator]();
console.log(it1.next()); // {value: 1, done: false}
console.log(it1.next()); // {value: 2, done: false}
console.log(it1.next()); // {value: 3, done: false}
console.log(it1.next()); // {done: true}

const it2 = iterable[Symbol.iterator]();
console.log(it2.next()); // {value: 1, done: false}
console.log(it2.next()); // {value: 2, done: false}
console.log(it2.next()); // {value: 3, done: false}
console.log(it2.next()); // {done: true}

Think of iterables as collections that can be iterated over, multiple times.

There are language constructs that make this iteration a lot friendlier. The two example we’ll look into are the for..of loop and array destructuring.

for (let e of iterable) {
	console.log(e); // 1, 2, 3
}
console.log([...iterable]); // [1, 2, 3]

There are also some functions that accept iterables, for example, the Array.from():

console.log(Array.from(iterable)); // [1, 2, 3]

While not all third-party libraries that provide collections embrace the iterable protocol, some do. For example, ImmutableJS collections are all iterables, making them compatible with the for..of loop:

for (let e of Immutable.List.of(1, 2, 3)) {
	console.log(e); // 1, 2, 3
}
for (let e of Immutable.Set.of(1, 2, 3)) {
	console.log(e); // 1, 2, 3
}

Also, you can use any iterable to construct Immutable Lists:

console.log(Immutable.List(iterable)); // List [1, 2, 3]

In effect, wherever you expect an iterable, you can use Arrays, custom-built iterables, Immutable collections, and any other compatible third-party data types.

Conclusion

Iterables are what make iterators actually useful. They abstract away the essence of collections, that is the ability to produce elements. If you need just that, different implementations become interchangeable on the language level.

On the downside, hand-writing iterables is still tedious.

In the next post, you’ll learn the basics of generators, which are a special kind of functions that make this syntax a lot more developer-friendly.

05 September 2017

Interesting article?

Get hand-crafted emails on new content!