Что это такое
Паттерн Iterator проходит по коллекции, не раскрывая, как она хранится. Вызывающий код просит только следующий элемент — а живут ли данные в массиве, в дереве или в базе данных, остаётся скрытым.
В TypeScript этот паттерн встроен. Класс, который определяет метод [Symbol.iterator](), можно обойти циклом for...of, и проще всего написать этот метод как генератор: функцию, помеченную *, которая отдаёт значения одно за другим через yield.
Пример: обход плейлиста
Плейлист держит свой массив песен приватным. Он предоставляет только [Symbol.iterator](), написанный как генератор, — хранилище за ним может полностью измениться, и ни один вызывающий код не сломается.
Генератор и for...of
Цикл никогда не трогает массив внутри плейлиста; он лишь просит следующую песню и выводит играет: intro, играет: verse, играет: chorus. Замените массив на связный список или на ленивую загрузку — и этот цикл по-прежнему будет работать.
Вывод: программа на TypeScript и захваченный вывод
class Playlist {
private songs: string[]
constructor(songs: string[]) {
this.songs = songs
}
// Генератор выдаёт по одной песне за раз; массив остаётся приватным.
*[Symbol.iterator](): Generator<string> {
for (const song of this.songs) {
yield song
}
}
}
const playlist = new Playlist(["intro", "verse", "chorus"])
for (const song of playlist) {
console.log("играет:", song)
}
Когда его использовать
Используйте его, когда внутреннее устройство коллекции должно оставаться приватным, когда обход нетривиален (деревья, страницы из API) или когда нужно несколько независимых обходов одновременно.
Не используйте его для обычных массивов и Map в вашем собственном коде — они уже итерируемы, поэтому for...of работает с ними напрямую.
Плюсы и минусы
Плюсы: хранилище остаётся приватным и заменяемым; каждый for...of получает свой независимый обход; сложный обход пишется один раз; генератор ленив — он вычисляет следующее значение только тогда, когда его просят.
Минусы: кода больше, чем при открытом доступе к массиву; живой итератор над изменяющейся коллекцией — классический источник тонких ошибок.