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 specs as obj[@@iterator]()
, that returns an iterator. It is not currently specified how to give your own objects such an internal method.
A generator is a specific type of iterator which also has a throw
method, and whose next
method takes a parameter.
A generator function is the source of a generator; you can send values or exceptions into the body of the function via the returned generator's next
and throw
methods. They are created with function*
syntax.
A generator expression is a shorthand for creating generators, e.g. (for (x of a) for (y of b) x * y)
.
An iterator can also be iterable if it has a @@iterator()
internal method. Most iterators in the ES6 spec are also iterable. In particular, all generators are iterable. So you can do
const lazySequence = (for (x of a) for (y of b) x * y);
for (let z in lazySequence) {
console.log(z);
}
As noted, there is no way specced yet to make an arbitrary object iterable, so in particular arbitrary objects cannot work with for
-of
yet.
for
-of
works on iterables, i.e. you do for (let x of iterable) { /* ... */ }
. So it works on arrays by looking up their @@iterator()
internal method, which is specified to return an iterator that does what you'd expect. Similarly it works on Map
s, Set
s, etc.
for
-in
has nothing to do with iterables, or indeed any of the concepts discussed here. It still works on enumerable object properties and will be pretty useless when given an iterable of any sort.
I am not sure why generator expressions create generators instead of simple iterable iterators. In particular I don't know what calling throw
or giving a parameter to next
would do.