相当于ES6生成器的Function.prototype.apply

Jus*_*eig 6 javascript v8 generator ecmascript-6

我正在尝试构建一个可链接的JavaScript API.(我在最新版本的V8中运行它,启用了迭代器和生成器.)在下面的示例中,setState是可链接的.它还允许您调用它而无需显式创建新Builder实例.该chain()辅助函数处理该自动返回该实例所以setState不必担心.(胜利的一流功能!)

除了可链接的方法,我想要一些"终止"方法.踢球者是这些"终结者"是发电机.生成器生成Builder实例的内部状态.问题是我无法弄清楚f.apply(that, arguments)发电机的等价物.我希望能够this在运行时调用生成器并设置其上下文,就像您可以使用Function.prototype.applyFunction.prototype.call.

解决方法Yuck!是在委托上公开委托原始生成器Builder.prototype,从委托调用原始生成器.有没有办法像chain方法一样实现等效包装而不必在_generate方法上公开方法Builder.prototype

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;
Run Code Online (Sandbox Code Playgroud)

哪个回报

[
  "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"
]
Run Code Online (Sandbox Code Playgroud)

Jus*_*eig 2

关键yield *gen.apply(that, arguments)在于匿名生成器包装器。

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;
Run Code Online (Sandbox Code Playgroud)