Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що повертає виклик генератора». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Виклик функції-генератора (`function*`) не запускає її код одразу: він повертає об'єкт-генератор, який є ітератором і керує виконанням цієї функції.** Цей об'єкт не є результатом обчислень, це «контролер», який дозволяє виконувати генератор покроково через `.next()`, `.throw()` і `.return()`. ```javascript function* gen() { yield 1; yield 2; } const iterator = gen(); console.log(iterator); // Object [Generator] {} console.log(iterator.next()); // { value: 1, done: false } console.log([...gen()]); // [1, 2] ``` **Ключове:** генератор повертає не значення, а ітератор; щоб отримати значення, його треба обійти через `.next()`, `for...of`, спред або `Array.from`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Виклик функції-генератора (`function*`) не запускає її код одразу: він повертає об'єкт-генератор, який є ітератором і керує виконанням цієї функції.** Тобто ви отримуєте не результат, а засіб, щоб виконувати тіло функції порціями. ## Теорія ### TL;DR - `gen()` не виконує жодного рядка тіла, він створює об'єкт-генератор. - Цей об'єкт є ітератором: у нього є `.next()`, `.throw()` і `.return()`. - Одночасно він є ітерованим об'єктом, бо має `[Symbol.iterator]()`. - Кожен `.next()` повертає `{ value, done }` і доводить виконання до наступного `yield`. - Щоб отримати всі значення одразу, генератор треба обійти: `for...of`, спред, `Array.from`. - Генератор не дорівнює результату функції: `numbers()` це не `[1, 2]`. ### Швидкий приклад ```javascript function* gen() { yield 1; yield 2; yield 3; } const iterator = gen(); // повертається об'єкт-генератор console.log(iterator); // Object [Generator] {} ``` Об'єкт `iterator` це не результат функції, а контролер, який дозволяє виконувати генератор покроково через `.next()`, `.throw()`, `.return()`. ### Два протоколи, які реалізує генератор Об'єкт-генератор одночасно реалізує два протоколи: 1. **Протокол ітератора**: метод `next()`, який повертає об'єкт з полями `value` і `done`. 2. **Протокол ітерованого об'єкта**: метод `[Symbol.iterator]()`, який повертає сам генератор. Саме тому той самий об'єкт можна і крутити вручну через `.next()`, і передати у `for...of`. ```javascript function* gen() { yield 'A'; yield 'B'; } const it = gen(); console.log(it.next()); // { value: 'A', done: false } console.log(it.next()); // { value: 'B', done: false } console.log(it.next()); // { value: undefined, done: true } ``` Кожен виклик `.next()`: - запускає генератор, якщо той «заморожений»; - виконує його до наступного `yield` або `return`; - повертає об'єкт `{ value, done }`. ### Генератор у for...of, спреді та Array.from Оскільки генератор ітерований, його можна використовувати всюди, де очікується ітерований об'єкт: ```javascript function* gen() { yield 1; yield 2; yield 3; } const iterator = gen(); for (const n of iterator) { console.log(n); } ``` Вивід: ```javascript 1 2 3 ``` Так само працюють `[...gen()]` і `Array.from(gen())`. Важливо: обхід вичерпує генератор, тому повторний `for...of` по тому самому об'єкту не дасть жодного значення, потрібен новий виклик `gen()`. ### Три методи об'єкта-генератора | Метод | Що робить | | --- | --- | | `.next(value)` | Відновлює виконання до наступного `yield`; повертає `{ value, done }` | | `.throw(error)` | Кидає виняток усередину генератора (ловиться через `try/catch`) | | `.return(value)` | Завершує генератор і повертає `{ value, done: true }` | ### Генератор це не результат функції Про це найчастіше забувають: ```javascript function* numbers() { yield 1; yield 2; } const result = numbers(); // повертає не [1, 2], а об'єкт-генератор ``` Щоб отримати справжні значення, генератор треба обійти: ```javascript console.log([...numbers()]); // [1, 2] ``` або вручну викликати `.next()` кілька разів. Схематично це виглядає так: ```javascript ┌─────────────────────┐ │ function* numbers() │ │ { yield 1; yield 2; }│ └────────┬────────────┘ │ виклик ▼ ┌───────────────────────────────┐ │ Object [Generator] │ │ ├── next() │ │ ├── throw() │ │ ├── return() │ │ └── [Symbol.iterator]() │ └───────────────────────────────┘ ``` Підсумок: | Що повертає генератор | Об'єкт-генератор | | --- | --- | | Запускається одразу? | Ні | | Чи можна керувати виконанням? | Так, через `.next()` | | Чи реалізує протокол ітератора? | Так | | Як повертає значення? | Через `yield` | | Чи можна використати у `for...of` | Так | | Як повертає кінцеве значення | Через `return` або разом з `done: true` | ### Типові помилки - **Очікувати масив.** `numbers()` повертає об'єкт-генератор, а не `[1, 2]`; масив дає спред або `Array.from`. - **Думати, що тіло вже виконалося.** Навіть `console.log` на початку генератора не спрацює, доки не буде першого `.next()`. - **Двічі обходити той самий об'єкт-генератор.** Після `done: true` він вичерпаний; щоб пройти знову, викликайте функцію-генератор ще раз. - **Плутати значення `yield` і значення `return`.** Те, що повернув `return`, приходить разом з `done: true` і не потрапляє у `for...of`. - **Забувати, що `.return()` завершує генератор назавжди.** Наступні `.next()` віддаватимуть лише `{ value: undefined, done: true }`. - **Перевіряти `typeof gen()`.** Це завжди `'object'`, тому перевіряти тип так безглуздо; ознакою генератора є наявність методу `next` і `[Symbol.iterator]`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.