Master ES6 Iterators for Clean JavaScript Code
ES6 introduced the Iterator interface, enabling sequential access to iterable objects like Arrays, Sets, Maps, Strings, arguments, and custom objects. Iterators provide a standardized way to traverse data structures and are essential for for...of
loops. In this guide, you'll learn how to use ES6 iterators to write clean, efficient JavaScript code. We'll cover the basics of iterators, how to create custom iterators, and how to use generator functions to simplify iteration patterns. Let's get started!
1. What is an Iterator?
An iterator is an object with a next()
method that returns:
1 { value: currentValue, done: true/false }
done: false
→ More values remain.done: true
→ Iteration is complete.
Iteration Process:
- Create an iterator pointing to the start of the data structure.
- Call
next()
to move to the first element. - Keep calling
next()
to traverse through elements. - Stops when
done: true
is returned.
2. How to Create an Iterator
(1) Manually Implement an Iterator
1 function createIterator(arr) {2 let index = 0;3 return {4 next: function () {5 return index < arr.length6 ? { value: arr[index++], done: false }7 : { value: undefined, done: true };8 }9 };10 }1112 let iterator = createIterator(["a", "b", "c"]);13 console.log(iterator.next()); // { value: 'a', done: false }14 console.log(iterator.next()); // { value: 'b', done: false }15 console.log(iterator.next()); // { value: 'c', done: false }16 console.log(iterator.next()); // { value: undefined, done: true }
📌 Each call to next()
returns a value and moves forward.
(2) Use Symbol.iterator
for Built-in Iterables
All iterable objects (Array
, Set
, Map
, String
) have a default iterator accessible via Symbol.iterator
.
📌 Arrays, Strings, Sets, and Maps can be iterated directly.
(3) Create an Iterator for a Custom Object
Ordinary objects are not iterable by default but can be made iterable using Symbol.iterator
.
1 let myObj = {2 data: [10, 20, 30],3 [Symbol.iterator]: function () {4 let index = 0;5 return {6 next: () => {7 return index < this.data.length8 ? { value: this.data[index++], done: false }9 : { value: undefined, done: true };10 }11 };12 }13 };1415 let iter = myObj[Symbol.iterator]();16 console.log(iter.next()); // { value: 10, done: false }17 console.log(iter.next()); // { value: 20, done: false }18 console.log(iter.next()); // { value: 30, done: false }19 console.log(iter.next()); // { value: undefined, done: true }
📌 Objects require Symbol.iterator
to be iterable with for...of
.
3. How to Use for...of
for Iteration
All objects implementing Symbol.iterator
can be traversed using for...of
.
1 let arr = ["A", "B", "C"];2 for (let char of arr) {3 console.log(char);4 }5 // A6 // B7 // C
📌 Unlike forEach()
, for...of
allows break
and continue
.
4. What Are Iterable Objects?
✅ Objects supporting for...of
via Symbol.iterator
:
Array
String
Set
Map
arguments
NodeList
- Custom objects (with
Symbol.iterator
implemented)
5. How to Iterate Over Set
and Map
(1) Iterate Over a Set
1 let mySet = new Set(["apple", "banana", "cherry"]);2 let setIter = mySet[Symbol.iterator]();34 console.log(setIter.next()); // { value: 'apple', done: false }5 console.log(setIter.next()); // { value: 'banana', done: false }6 console.log(setIter.next()); // { value: 'cherry', done: false }7 console.log(setIter.next()); // { value: undefined, done: true }
📌 Set maintains insertion order and ensures unique values.
(2) Iterate Over a Map
1 let myMap = new Map([2 ["name", "Alice"],3 ["age", 25]4 ]);56 for (let [key, value] of myMap) {7 console.log(key, value);8 }9 // name Alice10 // age 25
📌 Map
iteration returns [key, value]
pairs.
6. How Iterators Compare to Generators
The key differences between Iterators and Generators lie in their creation and execution patterns. For creation, Iterators require manual implementation of the next()
function and Symbol.iterator
, making them more verbose to write. Generators, on the other hand, use the function* syntax which automatically generates these implementations, significantly reducing boilerplate code.
When it comes to execution, Iterators run without pausing – they process their elements continuously until completion. In contrast, Generators support the yield keyword, allowing them to pause execution and resume later. This makes Generators particularly useful for controlling flow and managing memory in large datasets or infinite sequences.
Example: Using a Generator
1 function* generatorFunction() {2 yield "A";3 yield "B";4 yield "C";5 }67 let gen = generatorFunction();8 console.log(gen.next()); // { value: 'A', done: false }9 console.log(gen.next()); // { value: 'B', done: false }10 console.log(gen.next()); // { value: 'C', done: false }11 console.log(gen.next()); // { value: undefined, done: true }
📌 Generators simplify iteration with yield
and can pause execution.
7. Best Practices for Using Iterators
(1) Implement Iterators in a Class
1 class Collection {2 constructor() {3 this.items = [];4 }56 add(item) {7 this.items.push(item);8 }910 *[Symbol.iterator]() {11 for (let item of this.items) {12 yield item;13 }14 }15 }1617 let collection = new Collection();18 collection.add('foo');19 collection.add('bar');2021 for (let value of collection) {22 console.log(value);23 }24 // foo25 // bar
(2) Use Asynchronous Iterators (ES2018)
1 const asyncIterable = {2 async *[Symbol.asyncIterator]() {3 yield 'hello';4 yield 'async';5 yield 'iteration';6 }7 };89 (async () => {10 for await (const x of asyncIterable) {11 console.log(x);12 }13 })();14 // hello15 // async16 // iteration
8. When to Use Iterators
✅ Iterators are useful for:
- Traversing arrays, strings, sets, and maps
- Creating custom iterable objects
- Handling streaming data (e.g., paginated API responses)
- Avoiding memory-heavy operations by using generators
9. Conclusion
- Iterators
(Symbol.iterator
) provide a structured way to access collections. for...of
simplifies iteration over iterable objects.- Generators (
function*
) create iterators effortlessly with yield. - Asynchronous Iterators (
Symbol.asyncIterator
) handle streaming data efficiently.
Mastering iterators will make your JavaScript code more efficient and readable! 🚀