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 takefunction* 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, generatorconst 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 автоматически реализуют оба протокола.