Digging deep under the hood of GeneratorFunction and Generators. I want to add useful properties to the IteratorResult and possibly to the IteratorResult.value itself. This is all part of a grand scheme to take over the world. But I wonder how I can get a hold of the actual Iterator which the Generator function provides?
First I notice that a generator function itself when being executed has no this value (it's the global object), regardless if it was called first or continues after next():
function* range(start = 0, end = Infinity, step = 1) {
console.debug("awon", this);
for(let i = start; Math.sign(step)*(end - i) > 0; i += step) {
console.debug("tawoo", this);
i = (yield i)||i; // capricious trickery allowing us to go back or skip with next(arg)
console.debug("esree", this);
}
}
Now I make myself a useful side-entrance to do all sorts of magic to Generators (like define functions map, reduce, filter, etc.):
const Generator_prototype = Object.getPrototypeOf(range.prototype);
and with that, here I want to trap the provision of the Iterator object itself:
const originalIterate = Generator_prototype[Symbol.iterator];
function iterate() {
console.log("iter", this);
const iterator = originalIterate.apply(this);
iterator.parent = this;
return iterator;
}
Generator_prototype[Symbol.iterator] = iterate;
because, like I said, I want to massage the IterationResult coming from next():
const originalNext = Generator_prototype.next;
function next(...args) {
console.log("next", this);
let value = originalNext.apply(this, args);
if(this.decorate)
value = this.decorate(value);
return this.current = value;
}
Generator_prototype.next = next;
And with this:
[...range(1,3)]
gives the output:
iter range {<suspended>}
next range {<suspended>, parent: range}
next range {<suspended>, parent: range, current: {…}}
next range {<suspended>, parent: range, current: {…}}
> (2) [1, 2]
so, I never got a hold of the Iterable, only the Iterator. The function [Symbol.iterator] is called on some object, but that object somehow has the thisArg bound to the iterator that it is supposed to return. Notably:
iterator = range(1,3)[Symbol.iterator]()
iterator.parent == iterator // > true
how can that even happen? I am replacing the @@iterator method with my own, and when it is called it already has an iterator as the thisArg, which is the exact same iterator that I would get if I am asking for the standard iterator by applying the originalIterator to the this? My head is spinning!
How can I get a hold on the iterable, not the iterator?