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