Want an array’s values rather than its indices? `for...in` visits the indices; `for...of` can visit the values. That works because arrays follow the iterable protocol, a shared way for objects to supply a sequence of values. Strings, Sets, and Maps are iterable too. section 23.0 section 23.1
An iterable has a `[Symbol.iterator]` method, also called `@@iterator`. Calling it returns a new iterator. The iterator’s `next()` method returns an object containing `value`, the next item, and `done`, which signals completion. `for...of` and spread keep requesting items until `done` is true. section 23.4 section 23.5
Supply three values
A generator makes a short iterator without writing `next()` by hand: function* primesIterator() { yield 2; yield 3; yield 5; } const primesIterable = { [Symbol.iterator]: primesIterator }; const primes = [...primesIterable]; // [2, 3, 5] Spread calls the iterable’s method, receives an iterator, and collects its values. A hand-written iterator can do the same job by returning `{ value, done }` from each `next()` call. section 23.4
The method can also change how an existing object yields values. For example, an overridden string iterator can yield words instead of characters. Be careful with an infinite iterator: spread cannot finish collecting it. section 23.4
Quick check: write `take(n, iterable)` to collect at most `n` values, stopping sooner if the iterator finishes. Try it with an infinite iterable and take its first ten values. section 23.5

