JavaScript предоставляет гибкий инструмент — генераторы: функции, последовательно выдающие результаты. Рассмотрим их функционирование и применение.
Создание функции-генератора
Для создания функции-генератора после ключевого слова function ставится звёздочка (*). Звёздочка указывает, что функция будет генератором. Например:
function* strGenerator() {
// ...
}
Внутри генератора используется ключевое слово yield. yield порционно выдает результат. Например, для вывода строки «Hello» посимвольно:
function* strGenerator() {
yield 'H';
yield 'e';
yield 'l';
yield 'l';
yield 'o';
}
Работа с генератором
Вызов функции-генератора возвращает объект-итератор с методом next(). Каждый вызов next() возвращает объект с двумя свойствами: value (выданное значение) и done (флаг завершения генератора).
const str = strGenerator();
console.log(str.next()); // { value: 'H', done: false }
console.log(str.next()); // { value: 'e', done: false }
console.log(str.next().value); // 'l'
// ... и так далее
console.log(str.next()); // { value: undefined, done: true }
После обработки всех значений yield, done становится true, а value — undefined.
Генераторы с параметрами и циклом
Генераторы могут принимать параметры:
function* numberGen(n = 10) {
for (let i = 0; i < n; i++) {
yield i;
}
}
const numbers = numberGen(7);
console.log(numbers.next()); // { value: 0, done: false }
// ... и так далее
Этот пример демонстрирует генератор последовательности чисел от 0 до n-1.
Итераторы и Symbol.iterator
Цикл for…of предназначен для итерации по итерируемым объектам. Он использует специальный символ Symbol.iterator. Если у объекта есть свойство Symbol.iterator, возвращающее итератор с методом next(), то for…of может по нему итерироваться.
for (let key of "Hello") {
console.log(key); // Выводит посимвольно: H, e, l, l, o
}
const fibonacci = [1, 1, 2, 3, 5, 8, 13];
for (let num of fibonacci) {
console.log(num); // Выводит элементы массива
}
Строки и массивы имеют встроенное свойство Symbol.iterator. Для собственных объектов его необходимо добавить:
const iteratorWithSymbol = {
*[Symbol.iterator]() {
yield 10;
yield 20;
yield 30;
}
};
for (let value of iteratorWithSymbol) {
console.log(value); // Выводит 10, 20, 30
}
Теперь iteratorWithSymbol итерируется циклом for…of. *[Symbol.iterator]() — это генераторная функция, автоматически добавляющая необходимое свойство.
Генераторы и for…of
Генераторы автоматически имеют свойство Symbol.iterator, поэтому их можно использовать непосредственно в цикле for…of:
function* iterGen(n = 10) {
for (let i = 0; i < n; i++) {
yield i;
}
}
for (let i of iterGen(6)) {
console.log(i); // Выводит 0, 1, 2, 3, 4, 5
}
Генераторы — мощный инструмент для создания итераторов в JavaScript. Они упрощают работу с последовательностями данных и хорошо взаимодействуют с циклом for…of благодаря встроенному свойству Symbol.iterator. Выбор между генераторами и ручной реализацией итератора зависит от задачи.