ES6 Iterators, Generators, and Iterables

I wrote up a quick guide to the terminology around ES6’s iteration-related concepts, plus some notes and other
resources.

Definitions

An iterator is an object with a next method that returns { done, value } tuples.

An iterable is an object which has an internal method, written in the current ES6 draft specs as
obj[@@iterator](), that returns an iterator.

A generator is a specific type of iterator whose next results are determined by the behavior of its corresponding
generator function. Generators also have a throw method, and their next method takes a parameter.

A generator function is a special type of function that acts as a constructor for generators. Generator function
bodies can use the contextual keyword yield, and you can send values or exceptions into the body, at the points where
yield appears, via the constructed generator’s next and throw methods. Generator functions are written with
function* syntax.

A generator comprehension is a shorthand expression for creating generators, e.g.
(for (x of a) for (y of b) x * y).

Notes

for-of

The new for-of loop works on iterables, i.e. you do for (let x of iterable) { /* ... */ }. So for example, it
works on arrays by looking up their Array.prototype[@@iterator]() internal method, which is specified to return an
iterator that does what you’d expect. Similarly Map.prototype, Set.prototype, and others all have @@iterator
methods that help them work with for-of and other constructs in the language that consume iterators.

Note that for-in has nothing to do with iterables, or indeed any of the concepts discussed here. It still works as
it did before, looping through enumerable object properties, and it will be pretty useless when given an iterable of any
sort.

Iterable Iterators

An iterator can also be iterable if it has an @@iterator() internal method. Most iterators in the ES6 draft spec
are also iterable, with the internal method just returning this. In particular, all generators created via generator
functions or generator comprehensions have this behavior. So you can do:

Making Iterable Objects

To make a custom iterable object, you use the Symbol.iterator symbol, which is the inside-JavaScript way of referring
to the specification’s @@iterator. It should return an iterator, thus making your object iterable. The easiest way to
write the iterator-returning method is to use generator syntax. Putting this all together, it looks like

Generator Comprehension Desugaring

You can think of generator comprehensions as “sugar” for writing out and immediately invoking a generator function, with
yields inserted implicitly at certain points. For example, the comprehension (for (x of a) for (y of b) x * y)
desugars to

(function*(){for(xofa){for(yofb){yieldx*y;}}}())

A Weirdness

It’s not entirely clear why generator comprehensions create generators instead of simple iterable-iterators. In
particular, as you can see from the above desugaring, calling throw or giving a parameter to next is pretty useless:

It seems the arguments in favor of generators instead of iterable-iterators are largely that it makes implementers’ jobs
easier, at least according to
this es-discuss thread I started.

Implementation Status

Due to the tireless work of Andy Wingo, V8 (Chrome) has support for generator functions, behind
the --harmony flag (or “Experimental JavaScript Features” in chrome://flags). It also has some form of for-of,
which only works with generators and with the custom iterables returned by Array.prototype.values and
Array.prototype.keys, but does not work with anything else (e.g. arrays themselves). I assume this is because the
iteration protocol has not been implemented yet. V8 does not have generator comprehensions.

SpiderMonkey (Firefox) has an old version of everything here, with outdated syntax and semantics. Over the last week or
so, Andy has submitted patches to update their generator implementation. He’s now working on for-of and the
iteration protocol in bug #907077; no word on generator
comprehensions. Note that SpiderMonkey, unlike V8, does not hide these features behind a default-off flag.

Chakra (Internet Explorer) is as always a complete mystery, with no transparency into their development cycle or even
priority list.

And I still haven’t forgiven JavaScriptCore (Safari) for its long period of forgetting to implement
Function.prototype.bind, so I haven’t even tried looking into their status.