Делегированный выход (звезда выхода, выход *) в функциях генератора

ECMAScript 6 должен приносить функции генератора и итераторы. Функция генератора (которая имеет синтаксис function*) возвращает итератор. Итератор имеет метод next, который при повторном вызове выполняет тело функции генератора, многократно приостанавливая и возобновляя выполнение при каждом операторе yield.

wiki ECMAScript 6 для генераторов также вводит оператор делегированного вывода yield* следующим образом:

Оператор yield* делегирует другому генератору. Это обеспечивает удобный механизм компоновки генераторов.

Что означает "делегировать другому генератору"? Как я могу использовать yield* для "удобного создания генераторов"?

[Вы можете играть с генераторами в Node v0.11.3 с флагом --harmony-generators.]

Ответ 1

Делегирование на другой генератор означает, что текущий генератор прекращает выдавать значения сам по себе, вместо этого получая значения, полученные другим генератором, пока он не исчерпает его. Затем он возобновляет создание собственных значений, если они есть.

Например, если secondGenerator() создает числа от 10 до 15, а firstGenerator() производит числа от 1 до 5, но передает secondGenerator() после создания 2, тогда значения созданный firstGenerator(), будет:

1, 2, 10, 11, 12, 13, 14, 15, 3, 4, 5

function* firstGenerator() {
    yield 1;
    yield 2;
    // Delegate to second generator
    yield* secondGenerator();
    yield 3;
    yield 4;
    yield 5;
}

function* secondGenerator() {
    yield 10;
    yield 11;
    yield 12;
    yield 13;
    yield 14;
    yield 15;
}

console.log(Array.from(firstGenerator()));

Ответ 2

function *gimme1to2_10to15_3to5() {
    var ten = gimme10to15();
    yield 1; yield 2;
    for (var i = 10; i <= 20; i++)
        yield *ten;
    yield 3; yield 4; yield 5;
    }

function *gimme10to15() {
    for (var i = 10; i <= 15; i++)
        var x = yield i;
    }

let gen = gimme1to2_10to15_3to5();

var ar = [];
for (var i = 0; i < 12; i++)
    {
    var r = gen.next();
    ar [i] = r.value + (r.done ? "!" : "..");
    }
console.log (ar.join (", "));

Результат

1.., 2.., 10.., 11.., 12.., 13.., 14.., 15.., 3.., 4.., 5.., undefined!

Примечания

  • Функция с yield * запрашивает 11 значений из внутреннего генератора, но получает только 10..15. Вызов yield * не имеет эффекта.

  • Значение сделано внутреннего генератора не влияет на сделанный, который возвращает его вызывающий.

  • Результат показывает undefined! в конце, потому что цикл тестирования записывается для перехода за пределы требуемого количества значений, чтобы показать генератор done = true

  • Этот вывод находится на полигоне ES6, Babel, а семантика, показанная выше, должна считаться предварительной на 5-й Фев 2016 г.

Ответ 3

Делегированный доход не должен делегировать другому генератору только, но любому iterator, поэтому первый ответ немного неубедительен. Рассмотрим этот простой пример:

`
function *someGenerator() {
    yield 0;
    yield [1,2,3]
    yield* [1,2,3] 
}

for (v of someGenerator()) {
    console.log(v);
}

`

Внутри генератора нет другой функции, но yield делегирует итератору Array Object Iterator; -)