简体   繁体   English

如何扩展Generator类?

[英]How to extend the Generator class?

I tried to filter a generator and had the expectation that this kind of general functionality must be defined anywhere in JavaScript, because it is defined for Arrays, but I can not find it. 我试图过滤一个生成器,并期望必须在JavaScript中的任何地方定义这种通用功能,因为它是为数组定义的,但我找不到它。 So I tried to define it. 所以我试着定义它。 But I can not extend the built-in generators. 但我不能扩展内置的发电机。

I have an example generator 我有一个示例生成器

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

generating some numbers. 产生一些数字。

[...make_nums()] // => Array [ 1, 2, 3 ]

If I build an array, I can filter the array by the use of the filter function for arrays. 如果我构建一个数组,我可以通过使用数组的filter函数来filter数组。

[...make_nums()].filter(n => n > 1) // => Array [ 2, 3 ]

But I do not want to build an array. 但我不想建立一个数组。 Instead I want to take the old generator and build a new filtering generator. 相反,我想采用旧的生成器并构建一个新的过滤生成器。 For this I wrote the following function. 为此我写了以下函数。

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

which can be used to do what I want. 这可以用来做我想要的。

[...filtered (make_nums(), n => n > 1)] // => Array [ 2, 3 ]

But this is a very general function, which can be applied to every generator in the same way the filter function can be applied to every Array . 但这是一个非常通用的函数,它可以应用于每个生成器,就像filter函数可以应用于每个Array So I tried to extend generators in general, but I do not understand how. 所以我试图扩展生成器一般,但我不明白如何。

The MDN documentation for generators suggests somehow that Generator.prototype may exist, but it does not seem to exist. 生成器的MDN文档以某种方式表明Generator.prototype可能存在,但它似乎不存在。 When I try to define something in Generator.prototype , I get the error 当我尝试在Generator.prototype定义一些东西时,我得到了错误

ReferenceError: Generator is not defined ReferenceError:未定义Generator

How can I extend the built-in Generator class? 如何扩展内置的Generator类?

With the traditional caveat that extending built-in prototypes is not necessarily the best idea, and that it's something to be done with caution, you can get the generator function prototype with 传统的警告说,扩展内置原型不一定是最好的想法,并且要谨慎做到这一点,你可以获得生成器函数原型

const genproto = Object.getPrototypeOf(function*(){});

With that you could add a filter() capability: 有了它,你可以添加filter()功能:

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

And thus: 因此:

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

will print [0, 2, 4, 6, 8] . 将打印[0, 2, 4, 6, 8]

To be clear: this answer is about extending the prototype for generator functions , not the generator objects themselves. 要明确:这个答案是关于扩展生成器函数的原型,而不是生成器对象本身。 Thus this will ensure that every generator function in the program can use that .filter() method and any other similar extension. 因此,这将确保程序中的每个生成器函数都可以使用.filter()方法和任何其他类似的扩展。

It turned out that I was confused about Generator and Iterable . 事实证明,我对GeneratorIterable感到困惑。 I thought I had to extend Generator , but it is actually sufficient to extend Iterable . 我以为我必须扩展Generator ,但实际上扩展Iterable就足够了。 And the fact that Iterable does not seem to be defined by JavaScript either, makes it easy to define it, to avoid problems with modifications of built-in prototypes. 事实上, Iterable似乎也没有被JavaScript定义,因此很容易定义它,以避免修改内置原型的问题。

This actually does what I tried to achieve. 这实际上做了我试图实现的目标。

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;
  });
};

I can create Iterables 我可以创建Iterables

make_nums = new Iterable(function* () { yield 1; yield 2; yield 3; });

can use them 可以使用它们

[...make_nums] // => Array [ 1, 2, 3 ]

and can filter them 并可以过滤它们

[...make_nums.filter(n => n > 1)] // => Array [ 2, 3 ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM