如何扩展 Generator 类?

cev*_*ing 7 javascript generator ecmascript-6

我试图过滤一个生成器,并期望这种通用功能必须在 JavaScript 中的任何地方定义,因为它是为数组定义的,但我找不到它。所以我试图定义它。但我无法扩展内置生成器。

我有一个示例生成器

function make_nums ()
{
  let nums = {};
  nums[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
  };
  return nums;
}
Run Code Online (Sandbox Code Playgroud)

生成一些数字。

[...make_nums()] // => Array [ 1, 2, 3 ]
Run Code Online (Sandbox Code Playgroud)

如果我构建一个数组,我可以通过使用数组的filter函数来过滤数组。

[...make_nums()].filter(n => n > 1) // => Array [ 2, 3 ]
Run Code Online (Sandbox Code Playgroud)

但我不想建立一个数组。相反,我想使用旧的生成器并构建一个新的过滤生成器。为此,我编写了以下函数。

function filtered (generator, filter)
{
  let g = {};
  g[Symbol.iterator] = function* () {
    for (let value of generator)
      if (filter(value))
        yield value;
  };
  return g;
}
Run Code Online (Sandbox Code Playgroud)

可以用来做我想做的事。

[...filtered (make_nums(), n => n > 1)] // => Array [ 2, 3 ]
Run Code Online (Sandbox Code Playgroud)

但这是一个非常通用的函数,它可以应用于每个生成器,就像该filter函数可以应用于每个Array. 所以我试图扩展一般的生成器,但我不明白如何。

生成器的 MDN 文档以某种方式暗示Generator.prototype可能存在,但它似乎不存在。当我尝试在 中定义某些内容时Generator.prototype,出现错误

参考错误:未定义生成器

如何扩展内置Generator类?

Poi*_*nty 5

传统的警告是,扩展内置原型不一定是最好的主意,而且要谨慎行事,您可以使用以下命令获取生成器函数原型

const genproto = Object.getPrototypeOf(function*(){});
Run Code Online (Sandbox Code Playgroud)

有了它,您可以添加一项filter()功能:

Object.defineProperty(genproto, "filter", {
  value: function*(predicate) {
    for (let value of this())
      if (predicate(value)) yield value;
  }
});
Run Code Online (Sandbox Code Playgroud)

因此:

console.log([... function*() {
    for (let i = 0; i < 10; i++) yield i;
  }.filter(value => value % 2 === 0)
]);
Run Code Online (Sandbox Code Playgroud)

将打印[0, 2, 4, 6, 8]

需要明确的是:这个答案是关于扩展生成器函数的原型,而不是生成器对象本身。因此,这将确保程序中的每个生成器函数都可以使用该.filter()方法和任何其他类似的扩展。


cev*_*ing 5

原来我对Generator和感到困惑Iterable。我以为我必须扩展Generator,但实际上扩展就足够了Iterable。而且IterableJavaScript 似乎也没有定义的事实使得定义它变得容易,以避免修改内置原型的问题。

这实际上完成了我试图实现的目标。

class Iterable {
  constructor (generator) {
    this[Symbol.iterator] = generator;
  }
}

Iterable.prototype.filter = function (predicate) {
  let iterable = this;
  return new Iterable (function* () {
    for (let value of iterable)
      if (predicate (value))
        yield value;
  });
};
Run Code Online (Sandbox Code Playgroud)

我可以创造 Iterables

make_nums = new Iterable(function* () { yield 1; yield 2; yield 3; });
Run Code Online (Sandbox Code Playgroud)

可以使用它们

[...make_nums] // => Array [ 1, 2, 3 ]
Run Code Online (Sandbox Code Playgroud)

并且可以过滤它们

[...make_nums.filter(n => n > 1)] // => Array [ 2, 3 ]
Run Code Online (Sandbox Code Playgroud)