[英]How to extend the Generator class?
我试图过滤一个生成器,并期望必须在JavaScript中的任何地方定义这种通用功能,因为它是为数组定义的,但我找不到它。 所以我试着定义它。 但我不能扩展内置的发电机。
我有一个示例生成器
function make_nums ()
{
let nums = {};
nums[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
return nums;
}
产生一些数字。
[...make_nums()] // => Array [ 1, 2, 3 ]
如果我构建一个数组,我可以通过使用数组的filter
函数来filter
数组。
[...make_nums()].filter(n => n > 1) // => Array [ 2, 3 ]
但我不想建立一个数组。 相反,我想采用旧的生成器并构建一个新的过滤生成器。 为此我写了以下函数。
function filtered (generator, filter)
{
let g = {};
g[Symbol.iterator] = function* () {
for (let value of generator)
if (filter(value))
yield value;
};
return g;
}
这可以用来做我想要的。
[...filtered (make_nums(), n => n > 1)] // => Array [ 2, 3 ]
但这是一个非常通用的函数,它可以应用于每个生成器,就像filter
函数可以应用于每个Array
。 所以我试图扩展生成器一般,但我不明白如何。
生成器的MDN文档以某种方式表明Generator.prototype
可能存在,但它似乎不存在。 当我尝试在Generator.prototype
定义一些东西时,我得到了错误
ReferenceError:未定义Generator
如何扩展内置的Generator
类?
传统的警告说,扩展内置原型不一定是最好的想法,并且要谨慎做到这一点,你可以获得生成器函数原型
const genproto = Object.getPrototypeOf(function*(){});
有了它,你可以添加filter()
功能:
Object.defineProperty(genproto, "filter", {
value: function*(predicate) {
for (let value of this())
if (predicate(value)) yield value;
}
});
因此:
console.log([... function*() {
for (let i = 0; i < 10; i++) yield i;
}.filter(value => value % 2 === 0)
]);
将打印[0, 2, 4, 6, 8]
。
要明确:这个答案是关于扩展生成器函数的原型,而不是生成器对象本身。 因此,这将确保程序中的每个生成器函数都可以使用.filter()
方法和任何其他类似的扩展。
事实证明,我对Generator
和Iterable
感到困惑。 我以为我必须扩展Generator
,但实际上扩展Iterable
就足够了。 事实上, Iterable
似乎也没有被JavaScript定义,因此很容易定义它,以避免修改内置原型的问题。
这实际上做了我试图实现的目标。
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;
});
};
我可以创建Iterables
make_nums = new Iterable(function* () { yield 1; yield 2; yield 3; });
可以使用它们
[...make_nums] // => Array [ 1, 2, 3 ]
并可以过滤它们
[...make_nums.filter(n => n > 1)] // => Array [ 2, 3 ]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.