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

Что это такое

Паттерн Iterator проходит по коллекции, не раскрывая, как она хранится. Вызывающий код просит только следующий элемент — а живут ли данные в массиве, в дереве или в базе данных, остаётся скрытым.

В TypeScript этот паттерн встроен. Класс, который определяет метод [Symbol.iterator](), можно обойти циклом for...of, и проще всего написать этот метод как генератор: функцию, помеченную *, которая отдаёт значения одно за другим через yield.


Пример: обход плейлиста

Плейлист держит свой массив песен приватным. Он предоставляет только [Symbol.iterator](), написанный как генератор, — хранилище за ним может полностью измениться, и ни один вызывающий код не сломается.

Генератор и for...of

Цикл никогда не трогает массив внутри плейлиста; он лишь просит следующую песню и выводит играет: intro, играет: verse, играет: chorus. Замените массив на связный список или на ленивую загрузку — и этот цикл по-прежнему будет работать.

Prompt
Напишите программу на TypeScript с паттерном «Итератор»: класс Playlist, который хранит массив песен приватным и реализует Symbol.iterator как генератор, отдающий каждую песню. Пройдите по плейлисту циклом for...of и выведите каждую песню.
Вывод: программа на TypeScript и захваченный вывод

Когда его использовать

Используйте его, когда внутреннее устройство коллекции должно оставаться приватным, когда обход нетривиален (деревья, страницы из API) или когда нужно несколько независимых обходов одновременно.

Не используйте его для обычных массивов и Map в вашем собственном коде — они уже итерируемы, поэтому for...of работает с ними напрямую.


Плюсы и минусы

Плюсы: хранилище остаётся приватным и заменяемым; каждый for...of получает свой независимый обход; сложный обход пишется один раз; генератор ленив — он вычисляет следующее значение только тогда, когда его просят.

Минусы: кода больше, чем при открытом доступе к массиву; живой итератор над изменяющейся коллекцией — классический источник тонких ошибок.