for-of
, early termination, iterators, and generators
If we terminate a loop early, for-of
invokes method .return()
of the iterator. Generators return generator objects (that implement both the Iterable interface and the Iterator interface). If we invoke .return()
on such an object, the generator is terminated. We can prevent that by overriding .return()
.
More information: https://exploringjs.com/es6/ch_iteration.html#sec_iteration-protocol-in-depth
Demonstration:
function logIter(iter) {
console.log('------');
// First element
for (const x of iter) {
console.log(x);
break;
}
// Remaining elements
for (const x of iter) {
console.log(x);
}
}
//========== .return() stops execution of generator
function* generator1() {
yield 'a';
yield 'b';
yield 'c';
}
const iter1 = generator1();
logIter(iter1);
//========== Overriding .return() so that generator keeps on going
function* generator2() {
yield 'd';
yield 'e';
yield 'f';
}
const iter2 = generator2();
iter2.return = () => {
console.log('RETURN');
// Result is only used by yield*
return {};
};
logIter(iter2);
//========== Array iterators are not affected by .return()
const arr = ['g', 'h', 'i'];
const iter3 = arr[Symbol.iterator]();
logIter(iter3);
//========== Output
// '------'
// 'a'
// '------'
// 'd'
// 'RETURN'
// 'e'
// 'f'
// '------'
// 'g'
// 'h'
// 'i'