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. 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.
[...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
. 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. When I try to define something in Generator.prototype
, I get the error
ReferenceError: Generator is not defined
How can I extend the built-in Generator
class?
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:
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]
.
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.
It turned out that I was confused about Generator
and Iterable
. I thought I had to extend Generator
, but it is actually sufficient to extend 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.
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
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 ]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.