Skip to main content

Ключове слово function*

Ключове слово 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* відрізняється від звичайної функції

Особливістьfunctionfunction*
Повертаєрезультат (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, інакше ви отримаєте проміси.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.