javascript - 当我每次函数调用创建一个新的生成器时,为什么这个生成器函数包装器会消耗迭代器?

标签 javascript iterator generator immutability

当直接减少新制作的序列时,我可以多次减少同一个序列,但是如果我尝试重复减少从 .map 创建的序列,它只能在第一次起作用吗?

我似乎正在消耗原始迭代器......但我不知道如何/在哪里。据我理解这段代码, Sequence::map 会构建一个新的生成器来在每次调用时进行迭代,因此它应该能够每次都重复使用相同的 seq 。有人可以帮助我理解我所缺少的吗?

// A wrapper for a generatorFn
class Sequence {

  constructor(generatorFn) {
    if (typeof generatorFn === "function") {
      this[Symbol.iterator] = generatorFn;
    } else {
      throw new Error("Cannot create Sequence from provided argument");
    }
  }


  static of(obj) {
    //Create a generatorFn from an iterable object  
    function* genFn() {
        for (const x of obj) {
        yield x;
      }
    }
    return new Sequence(genFn);
  }

  map(fn) {
    //Make a generator from the generator function
    const gen = this[Symbol.iterator]();

    //Make a new generator function that applies fn to each value
    function* mapGenFn() {
      for (const x of gen) {
        yield fn(x);
      }
    }

    // Create a new sequence using the new generator function
    return new Sequence(mapGenFn);
  }

    reduce(fn, initial) {
    let acc;
    let first = true;
    // Make a new generator from the seq's generator fn
    const gen = this[Symbol.iterator]();
    if (initial) {
      acc = initial
      // iterate on the new generator
      for (const x of gen) {
        acc = fn(acc, x);
      }
    } else {
        acc = this.fold(fn);
    }
    return acc;
  }

  fold(fn) {
    const gen = this[Symbol.iterator]();
    let first = true;
    let acc;
    for (const x of gen) {
        if (first) {
            acc = x;
          first = false;
        } else {
          acc = fn(acc, x);
        }
    }
    return acc;
  }
}

const seqA = Sequence.of([1,2,3])
console.log("SeqA1 is: ", seqA.reduce((acc, x) => acc + x)); // 6
console.log("SeqA2 is: ", seqA.reduce((acc, x) => acc + x)); // 6
console.log("SeqA3 is: ", seqA.reduce((acc, x) => acc + x)); // 6

const seqB = Sequence.of([1,2,3]).map(x => x + 1);
console.log("SeqB1 is: ", seqB.reduce((acc, x) => acc + x)); // 9
console.log("SeqB2 is: ", seqB.reduce((acc, x) => acc + x)); // undefined
console.log("SeqB3 is: ", seqB.reduce((acc, x) => acc + x)); // undefined

演示问题的 fiddle :https://jsfiddle.net/qsh9mupz/5/

最佳答案

const gen = this[Symbol.iterator]() 不会在您每次使用新序列时创建,而是仅在您调用 时创建一次。 map (…)。将该部分移至 mapGenFn 内:

map(fn) {
  const gen = this[Symbol.iterator]; // no call here!
  return new Sequence(function* mapGenFn() {
    for (const x of gen()) {
//                     ^^ create new iterator here every time the sequence uses mapGenFn
      yield fn(x);
    }
  });
}

关于javascript - 当我每次函数调用创建一个新的生成器时,为什么这个生成器函数包装器会消耗迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60083282/

相关文章:

javascript - 我可以使用 setAttribute 更改文本节点内的文本吗?

Python zip 对象只能使用一次。这是为什么?

java - 是否有一个 Java 类可以让我迭代最后 x 个元素?

java - java中遍历Avl树

python - 生成器表达式使用生成器创建后分配的列表

javascript - 在 React 中提升状态不会导致不必要的重新渲染吗?

javascript - Args 与 ArgTypes

将 keyCodes 转换为字符的 JavaScript 函数

JavaScript 生成器 : implement a ticket queue system

python - 使用 python 生成器高效创建 scipy.lil_matrix