Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Ключове слово function*». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`function*` оголошує функцію-генератор: під час виклику вона не виконується одразу, а повертає об'єкт-генератор (ітератор).** Цим об'єктом виконання керують вручну через `.next()`, `.throw()` і `.return()`, а всередині тіла `yield` призупиняє функцію і віддає проміжне значення назовні. ```javascript function* gen() { yield 1; yield 2; } const iterator = gen(); // тіло ще не виконувалося console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: undefined, done: true } ``` **Ключове:** зірочка перетворює функцію на генератор, тобто на код, який можна виконувати покроково, зупиняти на `yield` і продовжувати з того самого місця.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Ключове слово `function*` створює функцію-генератор, яка під час виклику не виконується одразу, а повертає об'єкт-генератор (ітератор).** Цей об'єкт дозволяє керувати виконанням функції вручну, за допомогою викликів `.next()`, `.throw()` і `.return()`. ## Теорія ### TL;DR - `function*` оголошує генератор; зірочка стоїть одразу після слова `function`. - Виклик генератора повертає ітератор, а не результат обчислень. - `yield` усередині тіла віддає значення назовні та призупиняє виконання до наступного `.next()`. - Об'єкт-генератор реалізує протокол ітераторів, тому працює у `for...of`. - `next(value)` передає значення назад усередину функції, у результат виразу `yield`. - `async function*` повертає асинхронний ітератор, який обходять через `for await...of`. ### Швидкий приклад ```javascript function* gen() { yield 1; yield 2; yield 3; } const iterator = gen(); // функція не виконується одразу console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: 3, done: false } console.log(iterator.next()); // { value: undefined, done: true } ``` - Перший виклик `gen()` повертає ітератор, а не результат. - Кожен `.next()` запускає виконання до наступного `yield`. - Після останнього `yield` функція завершується і віддає `done: true`. ### Синтаксис ```javascript function* functionName(params) { yield value1; yield value2; // ... } ``` - Зірочка (`*`) після слова `function` робить функцію генератором. - Ключове слово `yield` використовують усередині, щоб призупинити виконання і повернути проміжне значення. Записи `function* name()`, `function *name()` і `function * name()` рівноцінні, але усталений стиль це зірочка біля слова `function`. ### Як працює yield `yield` це «пауза» у функції-генераторі. Він робить три речі: 1. **повертає значення** назовні (поле `value`); 2. **призупиняє виконання** функції; 3. чекає наступного виклику `.next()`, щоб продовжити. ```javascript function* greet() { console.log('Початок'); yield 'Привіт'; console.log('Продовження'); yield 'Як справи?'; } const it = greet(); console.log(it.next().value); // "Привіт" console.log(it.next().value); // "Як справи?" console.log(it.next()); // done: true ``` Між двома `yield` виконання реально зупиняється, зі звичайною функцією такого досягти неможливо. ### Генератор це ітератор Об'єкт, який повертає `function*`, реалізує протокол ітераторів, тому його можна передати у `for...of`: ```javascript function* gen() { yield 1; yield 2; } for (const n of gen()) { console.log(n); } ``` Вивід: ```javascript 1 2 ``` Крім `.next()`, об'єкт-генератор має ще два методи: `.return(value)` достроково завершує генератор і віддає `{ value, done: true }`, а `.throw(error)` кидає помилку в точці поточного `yield`, тож її можна перехопити всередині тіла генератора звичайним `try/catch`. ### Чим function* відрізняється від звичайної функції | Особливість | `function` | `function*` | | --- | --- | --- | | Повертає | результат (`value`) | ітератор (generator object) | | Можна призупиняти виконання | Ні | Так, через `yield` | | Виконується одразу | Так | Ні, тільки на `.next()` | | Використовують для | звичайних операцій | лінивих обчислень, ітераторів, потоків | | Можна приймати значення назад | Ні | Так, через `next(value)` | ### Передавання значень назад і асинхронний варіант Аргумент `next(value)` потрапляє всередину генератора як результат того виразу `yield`, на якому виконання було зупинене. ```javascript function* conversation() { const name = yield 'Як тебе звати?'; yield `Привіт, ${name}!`; } const chat = conversation(); console.log(chat.next().value); // "Як тебе звати?" console.log(chat.next('Maria').value); // "Привіт, Maria!" ``` Перший `next()` запускає генератор, другий передає `'Maria'` назад, і це значення потрапляє в `const name`. Якщо додати `async`, усередині генератора можна використовувати `await` (ES2018): ```javascript async function* fetchChunks() { yield await Promise.resolve('Chunk 1'); yield await Promise.resolve('Chunk 2'); } for await (const chunk of fetchChunks()) { console.log(chunk); } ``` Асинхронні генератори повертають асинхронний ітератор, і перебирають їх через `for await...of`. Підсумок: | Властивість | Опис | | --- | --- | | `function*` | Оголошує функцію-генератор | | Що повертає | Ітератор (об'єкт з методами `.next()`, `.throw()`, `.return()`) | | Ключове слово всередині | `yield` | | Особливість | Код можна виконувати покроково і призупиняти | | Асинхронний варіант | `async function*` | | Основне застосування | Ітератори, ліниві обчислення, потоки даних, складні асинхронні процеси | ### Типові помилки - **Очікувати, що `gen()` поверне значення.** Виклик повертає об'єкт-генератор; щоб отримати значення, потрібен `.next().value`. - **Забути зірочку.** Без `*` слово `yield` у тілі функції стає синтаксичною помилкою (у strict mode) або звичайним ідентифікатором. - **Вважати, що код до першого `yield` виконується під час виклику.** Він виконається лише на першому `.next()`. - **Використовувати стрілкову функцію.** Стрілкові функції не можуть бути генераторами, форми `() => {}` із зірочкою не існує; для методів об'єкта чи класу є скорочений запис `*name() {}`. - **Ігнорувати `.return()` і `.throw()`.** Це штатні способи достроково завершити генератор або вкинути в нього помилку, а не екзотика. - **Перебирати `async function*` через звичайний `for...of`.** Потрібен `for await...of`, інакше ви отримаєте проміси.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.