Iterators
Introduction
The iterator protocol is JavaScript's standard way to pull values one at a time from a sequence. An iterator has a next() method that returns { value, done }. An iterable has a Symbol.iterator method that returns an iterator.
This protocol explains why arrays, strings, maps, sets, generators, spread, destructuring, and for...of all work together.
Why This Matters
Iterator questions test protocol-level JavaScript, not memorized APIs. They also prepare you to design custom collections that integrate with language syntax and to reason about lazy iteration performance.
Theory
Iterator protocol
An iterator is any object with a next() method. Each call returns an object with value and done. When done is true, iteration is complete.
Iterable protocol
An iterable is any object with a method at Symbol.iterator. That method returns an iterator. for...of, spread, array destructuring, Array.from, Map, and Set consume iterables.
Iterator vs iterable
An iterator produces values. An iterable can produce an iterator. Many objects are both: a generator object is iterable because its Symbol.iterator returns itself.
Fresh iterators matter
For reusable collections, Symbol.iterator should return a fresh iterator each time. Otherwise one loop can accidentally exhaust the collection for future consumers.
Visual Diagrams
iterable object
| has Symbol.iterator()
v
iterator object
| next()
v
{ value, done }Language features call `Symbol.iterator` and then repeatedly call `next()`.
Code Examples
Make a plain object iterable
This collection returns a fresh iterator, so it can be iterated more than once.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1var bag = {2 values: ['x', 'y'],3 [Symbol.iterator]: function () {4 var index = 0;5 var values = this.values;6 return {7 next: function () {8 if (index < values.length) {9 return { value: values[index++], done: false };10 }11 return { value: undefined, done: true };12 }13 };14 }15};16 17for (var value of bag) {18 console.log(value);19}20console.log([...bag].join('-'));Coding Exercises
Create an iterable numeric range object
MediumImplement createRange(start, end, step) that returns an iterable object. It should work with for...of, spread, positive steps, and negative steps. Throw if step is zero.
Interview Questions
1What is the difference between an iterator and an iterable?
An iterator has next() and produces { value, done }. An iterable has [Symbol.iterator]() and returns an iterator. for...of requires an iterable, not merely an object with next().
Follow-ups
- Why should reusable collections return fresh iterators?
- Are generator objects iterable?
2Which language features consume iterables?
for...of, spread syntax, array destructuring, Array.from, Promise.all, Map, Set, and many library APIs consume iterables through Symbol.iterator.
Quiz
1. What method must a custom object define to be consumed by `for...of`?
Summary
- An iterator has `next()` and returns `{ value, done }`.
- An iterable has `[Symbol.iterator]()` returning an iterator.
- Arrays, strings, maps, sets, and generators are iterable.
- Reusable custom collections should return a fresh iterator each time.
Cheat Sheet
Iterator: { next() { return { value, done }; } }.
Iterable: object with [Symbol.iterator]() returning an iterator.
Consumers: for...of, spread, destructuring, Array.from, Map, Set.
Best practice: fresh iterator for reusable collections.