Javascript за кулисами-переменная для генератора - PullRequest
0 голосов
/ 05 мая 2020

У меня есть вопрос о генераторе в Javascript.

Я столкнулся с приведенным ниже примером.

var gennumcollect = gennum();

for (var nums of gennumcollect) {
    console.log(nums)
}

function *gennum() {
  for (let i = 0; i < 150; i++) {
    yield i
  }
}

Я попытался настроить это, изменив генератор на обычную функцию.

как,

function gennum(){
for( let i=0; i<150; i++) {
return i}}

Причина, по которой я пытался настроить этот способ, заключается в том, что я думал, что генератор не важен для алгоритма (насколько я понимаю, генератор жизненно важен, когда я хочу что-то асинхронно, например, делать это одно за другим, а не все сразу) var gennumcollect = gennum ();

Похоже, что если я устанавливаю переменную и приравниваю ее к генератору, она сохраняет все результаты после итерации через генератор. Я прав?

Кроме того, в чем причина этого кода, использующего генератор, а не просто обычную функцию, и возвращающий значения и сохраняющий их в массиве или объекте?

Оригинал код, как показано ниже.

https://codesandbox.io/s/article-event-bubbling-and-delegation-3-xp4iy?from-embed

Ответы [ 2 ]

2 голосов
/ 05 мая 2020

Хотя генераторы часто связаны с асинхронными процессами, они гораздо более общие, чем это. В общем, функция генератора возвращает iterator, которое вы можете рассматривать как обобщение массива. По сути, итератор - это любой объект, способный создавать (возможно, бесконечную) последовательность значений.

Когда вы изменили функцию с генератора на обычную функцию, это изменило возвращаемое значение с итератора на простое старое значение. Проблема возникает здесь:

for (var nums of gennumcollect) { ...

Если gennumcollect представляет собой последовательность значений, тогда это имеет смысл, но это не так, если это просто число.

Если вы любопытно, попробуйте это: замените вашу gennum функцию на это:

function gennum() {
  return [1, 2, 3, 4, 5];
}

Ваш пример должен снова работать.

Подводя итог: root проблемы что l oop:

for (var nums of gennumcollect) { ...

ожидает, что gennumcollect будет iterable. Однако, когда вы изменили свою функцию с функции генератора на обычную функцию, она больше не возвращает iterable, а возвращает обычное значение. Чтобы решить эту проблему, gennum должен вернуть какой-то iterable (пример которого - Array).

1 голос
/ 05 мая 2020

Я попытался настроить это, изменив генератор на обычную функцию. например,

function gennum(){
for( let i=0; i<150; i++) {
return i}}

Это не работает, потому что первый return i завершает функцию. Вызов функции вернет значение 0. При повторном вызове вы все равно получите значение 0.

В чем причина использования этого кода, использующего генератор, а не просто обычную функцию, возвращающий значения и сохраняющий их в массиве или объекте?

В этом конкретном примере c вы можете вернуть массив из всех 150 значений. Так что это не лучший пример генератора.

Несколько ключевых моментов о функциях генератора и генераторах, которые они создают:

  • Генератор - это полезный способ создания последовательность, которая никогда не заканчивается. Код, использующий генератор, использует значение за раз. Напротив, вы не можете поместить последовательность, которая никогда не заканчивается в массиве.

  • Генераторы - очень полезный способ написать итераторы, чтобы код, использующий их, мог использовать одно значение в время. Рассмотрим, как вы пропускаете oop через массив. Вы можете l oop через значения генератора (итератора) аналогичным образом (или даже точно так же, через for-of).

  • Код функции генератора не должен быть простым l oop, хотя это обычное дело. Он может иметь произвольно сложные logi c, потому что вы можете делать все, что захотите, между yield s.

  • Генератор может потреблять значений, заданных для это с помощью кода, использующего его, а не просто , производящего значений, как это делает пример в вашем вопросе. Чтобы получить значения из кода, использующего его, код функции генератора использует значение результата yield. Чтобы код не использовал логику триггера генератора c в функции генератора.

В комментарии к вопросу, который вы сказали:

, я конкретно задаюсь вопросом: «var gennumcollect = gennum ();» Похоже, что переменная gennumcollect хранит доходность генератора. Я прав? вместо определения переменной, которая является генератором, вместо этого он фактически сохраняет значения.

Нет, он сохраняет генератор, который возвращает функция генератора. Генератор - это объект с методом next, который дает вам "следующее" значение от генератора, которое функция штрафует.

Когда вы вызываете функцию генератора, он создает и возвращает объект-генератор, который будет ходить через логи c функции. На данный момент в функции еще ничего не запущено. Код в функции генератора запускается только тогда, когда код вызывает next для получения "следующего" значения от генератора. Рассмотрим этот пример:

function* gennum() {
    console.log("gennum: Starting");
    for (let i = 0; i < 5; ++i) {
        console.log(`gennum: About to yield ${i}`);
        yield i;
        console.log(`gennum: Back from yield ${i}`);
    }
    console.log("gennum: Done");
}

console.log("main:   About to call `gennum`:");
const gen = gennum();
console.log("main:   Starting loop:");
for (const v of gen) {
    console.log(`main:   Got the value ${v}`);
}
.as-console-wrapper {
    max-height: 100% !important;
}

Обратите внимание, что вы не видите gennum: Starting, пока мы не запустили for-of l oop в основном скрипте.

Вы также можете вызвать next вручную, что позволяет вам вводить значения в генератор:

function* gennum() {
    console.log("gennum: Starting");
    for (let i = 0; i < 5; ++i) {
        console.log(`gennum: About to yield ${i}`);
        const v = yield i;
        console.log(`gennum: Back from yield ${i}, got value ${v}`);
    }
    console.log("gennum: Done");
}

console.log("main:   About to call `gennum`:");
const gen = gennum();

console.log("main:   1st call to `next`:");
let result = gen.next();
console.log(`main:   Result: ${JSON.stringify(result)}`);

console.log("main:   2nd call to `next`, passing in A:");
result = gen.next("A");
console.log(`main:   Result: ${JSON.stringify(result)}`);

console.log("main:   3rd call to `next`, passing in B:");
result = gen.next("B");
console.log(`main:   Result: ${JSON.stringify(result)}`);
.as-console-wrapper {
    max-height: 100% !important;
}
...