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 Maps, Sets, 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.