Перейти к содержимому

Iterators Protocol

В одной фразе: iterator protocol — соглашение из двух частей: iterable (объект с Symbol.iterator) и iterator (объект с next(){value, done}). Это основа for…of, spread, деструктуризации и yield*.

// Реализация iterator protocol вручную
function range(from, to, step = 1) {
return {
[Symbol.iterator]() { // делает объект iterable
let cur = from;
return { // возвращает iterator
next() {
if (cur <= to) {
const value = cur;
cur += step;
return { value, done: false };
}
return { value: undefined, done: true };
},
[Symbol.iterator]() { return this; } // iterator сам iterable
};
}
};
}
[...range(0, 10, 2)]; // [0, 2, 4, 6, 8, 10]
// Бесконечный iterator + lazy take
function* naturals(start = 1) { while (true) yield start++; }
function take(iterable, n) {
const result = [];
for (const val of iterable) {
result.push(val);
if (result.length >= n) break; // итерируем ровно n элементов
}
return result;
}
take(naturals(), 5); // [1, 2, 3, 4, 5]
// Break внутри for...of вызывает iterator.return() (если есть)
// Это важно для cleanup ресурсов в кастомных итераторах
// for...of работает с любым iterable — Map, Set, String, generator
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, val] of map) { // Map итерируется по [key, value] парам
console.log(key, val);
}
// Деструктуризация тоже через Symbol.iterator:
const [first, ...rest] = 'hello'; // String — iterable
// first = 'h', rest = ['e','l','l','o']
// Обычный объект — НЕ iterable по умолчанию:
// for (const x of {}) // TypeError: {} is not iterable
// Нужно: for (const x of Object.values(obj))

Итог: Iterator protocol — “duck typing” интерфейс. Всё, у чего есть Symbol.iterator, итерируемо. Generators автоматически реализуют оба протокола.