Equivalent to .prototype.apply for ES6

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" ] 
+5
source share
2 answers

The key was yield *gen.apply(that, arguments) in the anonymous generator shell.

 function Builder() { this.initialState = 'initialState'; }; Builder.prototype.setState = chain(function(k, v) { this[k] = v; }); Builder.prototype.generate = delegate(generate); // Reuses or creates a Builder instance and makes it `this` for calling `f`. // Returns the Builder instance. function chain(f) { return function() { var that = (this instanceof Builder) ? this : new Builder(); f.apply(that, arguments); // Pass through arguments return that; } } // Similar to `chain()` to create a Builder instance if it doesn't exist. // Generators are terminal, though, so this returns the FunctionGenerator. function delegate(gen) { return function*() { var that = (this instanceof Builder) ? this : new Builder(); that.setState('delegated', true); yield *gen.apply(that, arguments); } } 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; 
+2
source

The problem is that I cannot calculate the equivalent of f.apply (what, arguments) for the generator.

Judging by the ES6 project, you don't need an equivalent - you can just use the expression as it is. Generator functions (which build generator instances) are functions, and they inherit (via Generator.prototype ) from Function.prototype ; you can use .call and .apply for them, as well as for any other function.

So the following should work:

 function delegate(gen) { return function() { var that = (this instanceof Builder) ? this : new Builder(); that.setState('delegated', true); return gen.apply(that, arguments); // Pass through arguments } } 
+3
source

Source: https://habr.com/ru/post/1208765/


All Articles