Iterators
An iterator is an object that defines a sequence and potentially a return value upon completion. It's an object that implements the iterator protocol by having a next() method. The next() method returns an object with two properties: value and done. The value property is the value of the next item in the sequence. The done property is a boolean that is true if the iterator is done with its sequence.
Iterator Example 1
We're going to create an app object that has an array of baseball teams.
const app = {
teams: ['Red Sox', 'Yankees', 'Astros', 'Dodgers'],
};
We want to create an iterator that will iterate through this teams array and return the next team in the sequence. We need to create a function in the object called next that returns the next team in the sequence. We also need to create a variable called nextIndex that will keep track of the next team in the sequence.
The next() function should return an object with a value and a done property. The value property is the next team in the sequence. The done property is true when the sequence is complete.
const app = {
nextIndex: 0,
teams: ['Red Sox', 'Yankees', 'Astros', 'Dodgers'],
next() {
if (this.nextIndex >= this.teams.length) {
return { done: true };
}
const returnValue = { value: this.teams[this.nextIndex], done: false };
this.nextIndex++;
return returnValue;
},
};
We can call the next() function to get the next team in the sequence.
console.log(app.next()); // { value: 'Red Sox', done: false }
console.log(app.next()); // { value: 'Yankees', done: false }
console.log(app.next()); // { value: 'Astros', done: false }
console.log(app.next()); // { value: 'Dodgers', done: false }
console.log(app.next()); // { done: true }
We can use a while loop with our iterator.
let next1 = app.next();
while (!next1.done) {
console.log(next1.value);
next1 = app.next();
}
Now, even though this is an iterator, is not iterable such as a built int Array or Map in JavaScript. We can not use a for...of loop with our iterator.
for (const team of app) {
console.log(team); // TypeError: app is not iterable
}
In order for this to be iterable and work with a for...of loop, we need to add a Symbol.iterator to our object.
Iterator Example 2
In this example, we will do the same thing as the previous example, but we will use the built-in Symbol.iterator.
const app = {
teams: ['Red Sox', 'Yankees', 'Astros', 'Dodgers'],
[Symbol.iterator]: function () {
let nextIndex = 0;
return {
next: () => {
return nextIndex < this.teams.length
? { value: this.teams[nextIndex++], done: false }
: { done: true };
},
};
},
};
So here, we are using Symbol.iterator to create a function where we are returning an object that has a next() function. The next() function returns the next team in the sequence. If the sequence is complete, it returns done: true.
We can use the iterator like this:
const iterator = app[Symbol.iterator]();
console.log(iterator.next().value); // Red Sox
console.log(iterator.next().value); // Yankees
console.log(iterator.next().value); // Astros
console.log(iterator.next().value); // Dodgers
console.log(iterator.next().done); // true
We could also use this iterator in a while loop.
let next = iterator2.next();
while (!next.done) {
console.log(next.value);
next = iterator2.next();
}
Or we could use it in a for...of loop.
// For of loop
for (const team of app2) {
console.log(team); // Res Sox, Yankees, Astros, Dodgers
}
So we're creating our own iterators. You may not use this stuff right now as a beginner, but it's good to know that this is how iterators work.