The Iteration Protocol
The iteration protocol is a set of standards that allows JavaScript objects to define or customize their iteration behavior. It consists of two complementary protocols: Iterable and Iterator.
What Problem Does It Solve?
Section titled “What Problem Does It Solve?”Before ES6, iterating over custom data structures was inconsistent. You had to know if an object used for-in, Object.keys(), or custom methods like getNext(). The iteration protocol provides a unified way to traverse any data structure.
The Two Protocols
Section titled “The Two Protocols”| Protocol | Role | Who Implements |
|---|---|---|
| Iterable | Defines how to get an iterator | The collection itself |
| Iterator | Defines how to traverse values | The iterator object |
Relationship Diagram
Section titled “Relationship Diagram”┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Iterable │─────▶│ Iterator │─────▶│ Value │ │ │ │ │ │ │ │ Symbol.iterator│ │ next() │ │ done: false │ └──────────────┘ └──────────────┘ └──────────────┘ │ ▼ ┌──────────────┐ │ Done │ │ done: true │ └──────────────┘
text
How It Works
Section titled “How It Works”- An iterable is any object that has a
Symbol.iteratormethod. - Calling
obj[Symbol.iterator]()returns an iterator object. - The iterator has a
next()method. - Each call to
next()returns an object withvalueanddoneproperties. - When iteration is complete,
donebecomestrue.
Built-in Iterables
Section titled “Built-in Iterables”JavaScript has many built-in iterables:
- Array
- String
- Map
- Set
- TypedArray
- arguments object
- NodeList (DOM)
- Generator objects
Key Points
Section titled “Key Points”- An Iterable is any object that implements the
Symbol.iteratormethod. - An Iterator is any object that implements a
next()method returning{ value, done }. - The protocol enables
for...of, spread syntax (...), destructuring, andyield*. - Plain objects are NOT iterable by default.
Why Learn This?
Section titled “Why Learn This?”Understanding the iteration protocol allows you to:
- Create custom iterable data structures
- Understand how
for...ofworks internally - Build lazy evaluation sequences
- Debug generator behavior
- Implement your own data collections
Example Code
Section titled “Example Code”// Basic iterable implementationconst countdown = { start: 3, [Symbol.iterator]() { let current = this.start; return { next() { if (current >= 1) { return { value: current--, done: false }; } return { value: undefined, done: true }; }, }; },};
// Using the iterable with for...offor (const num of countdown) { console.log(num); // 3, 2, 1}
// Using with spread operatorconsole.log([...countdown]); // [3, 2, 1]
// Using with destructuringconst [first, second, third] = countdown;console.log(first, second, third); // 3 2 1
// Array is iterable by defaultconst array = [10, 20, 30];const iterator = array[Symbol.iterator]();
console.log(iterator.next()); // { value: 10, done: false }console.log(iterator.next()); // { value: 20, done: false }console.log(iterator.next()); // { value: 30, done: false }console.log(iterator.next()); // { value: undefined, done: true }
// String is iterableconst str = "hello";for (const char of str) { console.log(char); // 'h', 'e', 'l', 'l', 'o'}
// Set is iterableconst set = new Set(["a", "b", "c"]);for (const item of set) { console.log(item); // 'a', 'b', 'c'}
// Map is iterable (returns [key, value] pairs)const map = new Map([ ["name", "Alice"], ["age", 30],]);for (const [key, value] of map) { console.log(`${key}: ${value}`); // 'name: Alice', 'age: 30'}
// Checking if something is iterablefunction isIterable(obj) { return obj != null && typeof obj[Symbol.iterator] === "function";}
console.log(isIterable([1, 2, 3])); // trueconsole.log(isIterable("hello")); // trueconsole.log(isIterable(new Map())); // trueconsole.log(isIterable({ a: 1 })); // falseconsole.log(isIterable(null)); // false