<b>let serialNumberGenerator = counter(1000); </b>
<b>let sn1 = serialNumberGenerator.next(); // 1000 </b>
<b>let sn2 = serialNumberGenerator.next(); // 1001</b>
При работе с конечными коллекциями метод
<b>next()</b>
итератора возбуждают исключение
<b>Stoplteration</b>
, когда в коллекции не остается значений для выполнения очередной итерации.
<b>Stoplteration</b>
- это свойство глобального объекта в JavaScript 1.7. Его значением является обычный объект (без собственных свойств), зарезервированный специально для нужд завершения итераций. Обратите внимание, что
<i>Stoplteration</i>
не является функцией-конструктором, таким как
<b>TypeErгог()</b>
или
<b>RangeError().</b>
Ниже приводится пример метода
<b>rangelter(),</b>
возвращающего итератор, который выполняет итерации по целым числам в заданном диапазоне:
<b>// Функция, возвращающая итератор диапазона целых чисел </b>
<b>function rangelter(first, last) { </b>
<b> let nextValue = Math.ceil(first); </b>
<b> return {</b>
<b> next: function() {</b>
<b> if (nextValue > last) throw Stoplteration;</b>
<b> return nextValue++;</b>
<b> }</b>
<b> };</b>
<b>}</b>
<b>// Пример неудобной реализации итераций с помощью итератора диапазона,</b>
<b>let r = rangelter(1.5); // Получить объект-итератор</b>
<b>while(true) { // Теперь использовать его в цикле</b>
<b> try {</b>
<b> console.log(г.next()); // Вызвать метод next() итератора</b>
<b> catch(e) {</b>
<b> if (е == Stoplteration) break; // Завершить цикл по Stoplteration else throw e;</b>
<b> }</b>
<b>}</b>
Обратите внимание, насколько неудобно использовать объект-итератор в цикле из-за необходимости явно обрабатывать исключение
<b>Stoplteration</b>
. Из-за этого неудобства итераторы редко используются на практике непосредственно. Чаще используются итерируемые объекты. Итерируемый объект представляет коллекцию значений, по которым можно выполнять итерации. Итерируемый объект должен определять метод с именем
<b>__iterator__()</b>
(с двумя символами подчеркивания в начале и в конце), возвращающий объект-итератор для коллекции.
В JavaScript 1.7 в цикл
<b>for/in</b>
была добавлена возможность работы с итерируемыми объектами. Если значение справа от ключевого слова in является итерируемым объектом, то цикл
<b>for/in</b>
автоматически вызовет его метод
<b>__iterator__(), </b>
чтобы получить объект-итератор. Затем он будет вызывать метод
<b>next()</b>
итератора, присваивать возвращаемое им значение переменной цикла и выполнять тело цикла. Цикл
<b>for/in</b>
сам обрабатывает исключение
<b>Stoplteration</b>
, и оно никогда не передается программному коду, выполняемому в цикле. Пример ниже определяет функцию
<b>range(),</b>
возвращающую итерируемый объект (а не итератор), который представляет диапазон целых чисел. Обратите внимание, насколько проще выглядит цикл
<b>for/in</b>
при использовании итерируемого объекта диапазона по сравнению с циклом
<b>while</b>
, в котором используется итератор диапазона.
<b>// Вернуть объект, представляющий диапазон. </b>
<b>// Границы диапазона не изменяются </b>
<b>// и хранятся в замыкании.</b>
<b>// Диапазоны могут проверять вхождение, max;</b>
<b>// Возвращает итерируемый объект, представляющий диапазон чисел </b>
<b>function range(min,max) { return {</b>
<b> get min() { return min; }, </b>
<b> get max() { return max; },</b>
<b> includes: function(x) {</b>
<b> return min <= x && x <= max;</b>
<b> },</b>
<b> toString: function() { // Диапазоны имеют строковое представление,</b>
<b> return "[" + min + "," + max + "]";</b>
<b> },</b>
<b> __iterator__: function() { // Возможно выполнять итерации по диапазону</b>
<b> let val = Math.ceil(min); // Сохранить текущ. позицию в замыкании.</b>
<b> return { // Вернуть объект-итератор.</b>
<b> next: function() { // Вернуть следующее число в диапазоне.</b>
<b> if (val > max) // Если достигнут конец - прервать итерации</b>
<b> throw StopIteration;</b>
<b> return val++; // Иначе вернуть следующее число</b>
<b> } // и увеличить позицию</b>
<b> };</b>
<b> }</b>
<b> };</b>