I'm learning about iterators/generators, and am wondering if there is a way to make the iterator reset itself?
For example, when after you call the last .next()
is there a way to make it restart?
const arr = [ {name: "Bob"}, {name: "Peter"}, {name: "Sally"} ];
const names = nameGenerator(arr);
function nextName() {
const current = names.next().value;
const output = document.querySelector("output");
if (current) {
output.innerText = current.name;
}
else {
// code to reset it!
output.innerText = 'Nothing left';
}
}
function nameIterator(names) {
let nextIndex = 0;
return {
next: function () {
return nextIndex < names.length ?
{ value: names[nextIndex++], done: false } :
{ done: true };
}
}
}
function* nameGenerator() {
let index = 0;
while (index < arr.length) {
yield arr[index++];
}
}
document.querySelector("button").addEventListener("click", nextName)
<button>Iterate me!</button>
<output></output>
In this snippet, when you click the button, it calls my iterator which will display the names in my names array one by one each time you click. How can I make it reset on the last click so it goes back to the first name?
So the display would be like:
Bob Peter Sally Bob // get Bob again
I have also written the iterator using a generator, is there anyway for that to also be able to reset back to the first one after yielding through the array?
The general answer is that you can't reset an iterable in JS. This is, as far as I know, by-design, although I'm not privy to the decision-making process that was used to reach that conclusion.
In your specific case however, you don't want to necessarily reset the iterator, you want to cycle through the array. In that case, you can use the modulo operator as follows:
function nameIterator(names) {
let nextIndex = 0;
return {
next: function() {
nextIndex = (nextIndex + 1) % names.length;
return { value: names[nextIndex], done: false };
}
}
}