Генератори та ітератори
1. Що таке ітератори (коротко)
Ітератор - це об'єкт, який дозволяє поелементно перебирати значення.
Він повинен реалізовувати метод next(), який повертає об'єкт формату:
{
value: <значення>,
done: <булеве>
}Приклад простого ручного ітератора:
const iterator = {
current: 0,
next() {
if (this.current < 3) {
return { value: this.current++, done: false };
} else {
return { value: undefined, done: true };
}
}
};
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }Ітератор - це об'єкт, який знає, як видавати значення по одному.
2. Що таке генератор
Генератор (function*) - це зручний спосіб створити ітератор,
не реалізуючи next() вручну.
Коли ти викликаєш function*, вона повертає об'єкт-генератор,
який вже реалізує ітераторний протокол.
3. Генератор є ітератором
function* gen() {
yield 10;
yield 20;
yield 30;
}
const iterator = gen();
console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: 20, done: false }
console.log(iterator.next()); // { value: 30, done: false }
console.log(iterator.next()); // { value: undefined, done: true }iterator- це об'єкт-генератор;- у нього є метод
next(), що повертає{ value, done }; - отже, він повністю відповідає протоколу ітератора.
4. Генератор також є ітерованим об'єктом
Генератор реалізує не лише ітераторний, а й ітерований протокол,
тому що в нього є метод Symbol.iterator:
function* gen() {
yield 1;
yield 2;
yield 3;
}
const it = gen();
console.log(typeof it[Symbol.iterator]); // "function"
console.log(it[Symbol.iterator]() === it); // trueЦе означає, що генератор:
- можна використовувати в
for...of; - можна розпилювати (
...); - можна передавати в
Array.from(),Promise.all()тощо.
5. Приклад використання генератора як ітератора
function* numbers() {
yield 1;
yield 2;
yield 3;
}
for (const n of numbers()) {
console.log(n);
}Виведе:
1
2
3for...of автоматично викликає next() у генератора, поки done: false.
6. Зв'язок між ітераторами і генераторами
| Властивість | Ітератор | Генератор |
|---|---|---|
| Що це | Об'єкт з методом next() | Функція, що повертає ітератор |
| Повертає | { value, done } | { value, done } |
| Створюється вручну | так | ні, автоматично |
| Керує станом вручну | так | ні, автоматично всередині function* |
Можна використовувати в for...of | Тільки якщо реалізує [Symbol.iterator] | так (реалізовано типово) |
Тобто: генератори - це синтаксичний цукор над створенням ітераторів.
7. "Ручний ітератор" vs "генератор"
Без генератора:
function makeIterator(array) {
let i = 0;
return {
next() {
return i < array.length
? { value: array[i++], done: false }
: { value: undefined, done: true };
}
};
}
const it = makeIterator(['a', 'b', 'c']);
console.log(it.next()); // { value: 'a', done: false }З генератором:
function* makeIterator(array) {
for (const item of array) yield item;
}
const it = makeIterator(['a', 'b', 'c']);
console.log(it.next()); // { value: 'a', done: false }Генератори прибирають усю ручну логіку стану, зберігаючи при цьому ту саму поведінку.
8. Генератори дозволяють створювати "нескінченні ітератори"
function* infiniteCounter() {
let i = 1;
while (true) yield i++;
}
const it = infiniteCounter();
console.log(it.next().value); // 1
console.log(it.next().value); // 2
console.log(it.next().value); // 3Це неможливо зі звичайним масивом, але ітератори (і генератори) підтримують "ліниву" нескінченність.
ПІДСУМОК
| Концепція | Ітератор | Генератор |
|---|---|---|
| Що це | Об'єкт з методом next() | Функція, що повертає ітератор |
| Керування станом | Ручне | Автоматичне |
| Протокол | Ітераторний | Ітераторний + Ітерований |
Метод Symbol.iterator | Зазвичай потрібно додати вручну | Є типово |
Можна використовувати в for...of | Тільки якщо реалізований [Symbol.iterator] | завжди |
| Обчислення | Ліниві | Ліниві |
| Зручність | Низька | Висока |
Підсумок в одній фразі:
Генератор - це зручний спосіб створити ітератор, не реалізуючи вручну
next(),doneі внутрішній стан.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.