Генераторы ES6 — пример, когда нет выражения yield для первого next()

Что касается генераторов ES6, почему автор этого сообщения в блоге говорит:

из: http://davidwalsh.name/es6-generators

«При первом вызове next(..) мы ничего не отправляем. Почему? Потому что нет выражения yield для получения того, что мы передаем».

Разве первый it.next() не звонит (yield (x + 1))?

function *foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);
}

var it = foo( 5 );

// note: not sending anything into `next()` here
console.log( it.next() );       // { value:6, done:false }
console.log( it.next( 12 ) );   // { value:8, done:false }
console.log( it.next( 13 ) );   // { value:42, done:true }

Вы можете видеть, что мы все еще можем передавать параметры (x в нашем примере) с начальным вызовом итератора foo( 5 ), как и с обычными функциями.

При первом вызове next(..) мы ничего не отправляем. Почему? Потому что нет выражения yield для получения того, что мы передаем.


person dman    schedule 02.11.2014    source источник


Ответы (1)


Первый it.next() соответствует yield(x + 1), что, как и ожидалось, дает 6. 12 в следующем вызове it.next(12) устанавливает значение этого первого выхода равным 12, поэтому y удваивается, или 24, а итератор возвращает значение (y / 3), равное 8. Последний вызов it.next(13) устанавливает значение второй дает значение 13, для которого установлено значение z, и получает значение return, равное 5 + 24 + 13.

Конечно, это немного сбивает с толку из-за синтаксиса

z = yield(y / 3)

что каким-то образом выглядит так, как будто кто-то присваивает значение чего-то, связанного с y / 3, z. Это не так. y / 3 – это значение, которое передается в качестве значения итератора, тогда как z присваивается значению, переданному следующим вызовом it.next(), что-то совершенно другое! Может быть немного полезно опустить круглые скобки и записать это как

var y = 2 * yield x + 1;
var z = yield y / 3;

имея в виду, что yield — это оператор, а не вызов функции.

Что касается упомянутой вами ошибки, например, в traceur это «Отправлено значение в генератор новорожденных». Это имеет смысл, когда вы думаете об этом. Значение, отправляемое в качестве параметра it.next(), становится значением последней доходности в генераторе. При первом вызове it.next() в генераторе нет самого последнего результата yield, поэтому нечего принимать передаваемое значение, отсюда и ошибка.

Не путайте передачу параметров генератору (в вашем случае x), который просто обеспечивает способ настройки или инициализации генератора, с передачей параметров it.next(), которые служат значением самого последнего yield в генераторе.

Может быть полезно подумать о том, как бы вы написали эквивалентный ручной генератор (упрощенный, чтобы просто возвращать следующее значение вместо {value, done} и бросать, когда в генераторе нет газа):

function foo(x) {
    var y, z, step = 0;
    return function next(val) {
        switch (step++) {
            case 0:               return x + 1;      break;
            case 1: y = 2 * val;  return y / 3;      break;
            case 2: z = val;      return x + y + z;  break;
            default: throw "generator finished";
        }
    };
}

Затем:

iterator = foo(5);
iterator();             // 6
iterator(12);           // 8
iterator(13);           // 42
person Community    schedule 02.11.2014