I am trying to build a JavaScript JavaScript API. (Im working in the latest version of V8 with iterators and generators turned on.) In the example below, setState is setState . It also allows you to call it without having to explicitly create a new instance of Builder . The helper function chain() processes this and automatically returns this instance, so setState does not need to worry about it. (First-class features for victory!)
In addition to the chain methods, I need some "trailing" methods. The kicker is that these "terminators" are generators. Generators lead to the internal state of the Builder instance. The problem is that I cannot calculate the f.apply(that, arguments) equivalent for the generator. I want to be able to call the generator and set its this context at runtime, just as you can do with Function.prototype.apply and Function.prototype.call .
Crawl commented with Yuck! , is to show both the delegated and the source generator in Builder.prototype , invoking the original from the delegated. Is there a way to implement an equivalent wrapper such as the chain method without exposing the _generate method to the _generate method?
function Builder() { this.initialState = 'initialState'; }; Builder.prototype.setState = chain(function(k, v) { this[k] = v; }); Builder.prototype.generate = delegate(generate, '_generate'); // Yuck! Builder.prototype._generate = generate; function chain(f) { return function() { var that = (this instanceof Builder) ? this : new Builder(); f.apply(that, arguments); // Pass through arguments return that; } } function delegate(gen, _gen) { return function*() { var that = (this instanceof Builder) ? this : new Builder(); that.setState('delegated', true); yield *that[_gen](); // Yuck! } } function *generate(opts) { var i = 0; for(var i = 0; i < 10; i++) { yield [Object.keys(this), opts, i].join(','); } } // Set up a namespace var ns = {}; ns.setState = Builder.prototype.setState; ns.generate = Builder.prototype.generate; var itr = ns // .setState('a', 'A') // .setState('b', 'B') // .setState('c', 'C') .generate('options'); var out = []; for(var value of itr) { out.push(value); } out;
What returns
[ "initialState,delegated,,0", "initialState,delegated,,1", "initialState,delegated,,2", "initialState,delegated,,3", "initialState,delegated,,4", "initialState,delegated,,5", "initialState,delegated,,6", "initialState,delegated,,7", "initialState,delegated,,8", "initialState,delegated,,9" ]