Iterators
Iterators give us a standard way to walk through a sequence of values one at a time. The iteration protocol is the set of rules an object follows to hand out its values, and language features like the for...of loop and the spread operator rely on those rules.
The Iteration Protocol
JavaScript’s iteration is based on two protocols:
- Iterable protocol: An object is iterable if it has a
[Symbol.iterator]method that returns an iterator - Iterator protocol: An iterator is an object with a
next()method that returns{ value, done }
Built-in Iterables
Arrays, strings, Maps, Sets, and other collections are iterable:
const arr = [1, 2, 3];
// for...of uses the iterator
for (const item of arr) {
console.log(item); // 1, 2, 3
}
// Spread operator uses the iterator
console.log([...arr]); // [1, 2, 3]
// Array.from uses the iterator
console.log(Array.from(arr)); // [1, 2, 3]
Using an Iterator Directly
We do not have to go through for...of. We can get the iterator ourselves and call next() on it:
const arr = ["a", "b", "c"];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Creating Custom Iterators
Make any object iterable by implementing [Symbol.iterator]:
const range = {
start: 1,
end: 5,
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
}
return { done: true };
},
};
},
};
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
console.log([...range]); // [1, 2, 3, 4, 5]
Iterable Class Example
class Playlist {
constructor() {
this.songs = [];
}
add(song) {
this.songs.push(song);
}
[Symbol.iterator]() {
let index = 0;
const songs = this.songs;
return {
next() {
if (index < songs.length) {
return { value: songs[index++], done: false };
}
return { done: true };
},
};
}
}
const playlist = new Playlist();
playlist.add("Song A");
playlist.add("Song B");
playlist.add("Song C");
for (const song of playlist) {
console.log(song);
}