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.