function*

Оголошення function* (ключове слово function з зірочкою) визначає функцію-генератор, яка повертає об'єкт Generator.

Ви також можете визначати функції-генератори за допомогою конструктора GeneratorFunction або функціонального виразу.

Синтаксис

function* name([param[, param[, ... param]]]) {
   statements
}
name
Ім'я функції.
param
Ім'я формального параметра функції.
statements
Інструкції, що складають тіло функції.

Опис

Генератори - це функції, з яких можна вийти та пізніше повторно зайти. Їхній контекст (зв'язування змінних) збережеться між заходами.

Генератори у JavaScript -- особливо у поєднанні з промісами -- дуже потужний інструмент асинхронного програмування, бо вони пом'якшують -- якщо не усувають повністю -- проблеми зворотних викликів, такі як Пекло зворотних викликів та Інверсія управління.

Виклик функції-генератора не виконує тіло функції негайно; замість цього повертається об'єкт-ітератор для функції. Коли викликається метод ітератора next(), тіло функції-генератора виконується до першого виразу yield, який визначає значення, що має бути повернене ітератором, або, оператором yield*, делегується до іншої функції-генератора. Метод next() повертає об'єкт з властивістю value, що містить отримане значення, та властивістю done, яка вказує, чи генератор віддав останнє значення, у вигляді булевого значення. Виклик метода next() з аргументом відновить виконання функції-генератора, замінюючи вираз yield в тій точці, де виконання було призупинене, аргументом з next().

Оператор return у генераторі змусить генератор завершити виконання (тобто, властивості done поверненого об'єкта буде присвоєне значення true). Якщо повертається значення, воно буде присвоєте властивості value об'єкта, що повертається генератором.
Схоже на оператор return, викидання помилки всередині генератора змусить генератор завершити виконання -- якщо не буде перехоплене у тілі генератора.
Коли генератор завершує виконання, наступні виклики next не виконають жодного коду генератора, вони лише повернуть об'єкт наступного вигляду: {value: undefined, done: true}.

Приклади

Простий приклад

function* idMaker() {
  var index = 0;
  while (true)
    yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// ...

Приклад з yield*

function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i) {
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

Передача аргументів у об'єкти Generator

function* logGenerator() {
  console.log(0);
  console.log(1, yield);
  console.log(2, yield);
  console.log(3, yield);
}

var gen = logGenerator();

// перший виклик метода next виконує функцію з початку
// до першого оператора yield
gen.next();             // 0
gen.next('крендель');   // 1 крендель
gen.next('кава');       // 2 кава
gen.next('майонез');    // 3 майонез

Оператор return у генераторі

function* yieldAndReturn() {
  yield "Y";
  return "R";
  yield "недосяжний";
}

var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }

Генератор як властивість об'єкта

const someObj = {
  *generator () {
    yield 'а';
    yield 'б';
  }
}

const gen = someObj.generator()

console.log(gen.next()); // { value: 'а', done: false }
console.log(gen.next()); // { value: 'б', done: false }
console.log(gen.next()); // { value: undefined, done: true }

Генератор як метод класу

class Foo {
  *generator () {
    yield 1;
    yield 2;
    yield 3;
  }
}

const f = new Foo ();
const gen = f.generator();

console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

Генератор як обчислювана властивість

class Foo {
  *[Symbol.iterator] () {
    yield 1;
    yield 2;
  }
}

const SomeObj = {
  *[Symbol.iterator] () {
    yield 'а';
    yield 'б';
  }
}

console.log(Array.from(new Foo)); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'а', 'б' ]

Генератори не є конструкторами

function* f() {}
var obj = new f; // викидає "TypeError: f is not a constructor

Генератор, визначений у виразі

const foo = function* () {
  yield 10;
  yield 20;
};

const bar = foo();
console.log(bar.next()); // {value: 10, done: false}

Специфікації

Специфікація Статус Коментар
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'function*' in that specification.
Standard Початкове визначення.
ECMAScript 2016 (ECMA-262)
The definition of 'function*' in that specification.
Standard Внесено зміни, що генератори не повинні мати пастки [[Construct]] та викидатимуть помилку при використанні з new.
ECMAScript Latest Draft (ECMA-262)
The definition of 'function*' in that specification.
Draft

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
function*Chrome Full support 39Edge Full support 13Firefox Full support 26IE No support NoOpera Full support 26Safari Full support 10WebView Android Full support YesChrome Android Full support 39Firefox Android Full support 26Opera Android Full support YesSafari iOS Full support 10Samsung Internet Android Full support 4.0nodejs Full support 4.0.0
Full support 4.0.0
Full support 0.12
Disabled
Disabled From version 0.12: this feature is behind the --harmony runtime flag.
IteratorResult object instead of throwingChrome Full support 49Edge Full support 13Firefox Full support 29IE No support NoOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support 49Firefox Android Full support 29Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes
Not constructable with new (ES2016)Chrome Full support 50Edge Full support 13Firefox Full support 43IE No support NoOpera Full support 37Safari Full support 10WebView Android Full support 50Chrome Android Full support 50Firefox Android Full support 43Opera Android Full support 37Safari iOS Full support 10Samsung Internet Android Full support 5.0nodejs Full support Yes
Trailing comma in parametersChrome Full support 58Edge Full support 14Firefox Full support 52IE No support NoOpera Full support 45Safari ? WebView Android Full support 58Chrome Android Full support 58Firefox Android Full support 52Opera Android Full support 43Safari iOS ? Samsung Internet Android Full support 7.0nodejs Full support 8.0.0

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
User must explicitly enable this feature.
User must explicitly enable this feature.

Примітки щодо Firefox

Генератори та ітератори у Firefox до 26-ї версії

Старші версії Firefox реалізують старшу версію пропозиції генераторів. У старшій версії генератори визначались за допомогою звичайного ключового слова function (без зірочки), серед інших відмінностей. Дивіться більше інформації у статті Застаріла функція-генератор.

Замість викидання помилки повертається об'єкт IteratorResult

Починаючи з Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26), завершена функція-генератор більше не викидає помилку TypeError "generator has already finished". Замість цього, вона повертає об'єкт IteratorResult у вигляді { value: undefined, done: true } (bug 958951).

Див. також