如何识别ES6发电机

时间:2014-02-04 17:30:07

标签: javascript generator ecmascript-harmony

说我有这样的生成器函数:

var g = function*() {
  yield 1;
  yield 2;
  yield 3;
};

var gen = g();

如何以编程方式告诉g是生成器函数,还是gen是迭代器?

这似乎是一种可能性:

g.constructor.name === 'GeneratorFunction'

有更好的方法吗?

更新:我最终taking an approachEric's answer类似,但使用eval首先确定目标平台是否支持生成器。以下是实施:

var GeneratorConstructor = (function() {
  try {
    var generator;
    return eval('generator = function*() { yield 1; };').constructor;

  } catch (e) {
    // If the above throws a SyntaxError, that means generators aren't
    // supported on the current platform, which means isGenerator should
    // always return false. So we'll return an anonymous function here, so
    // that instanceof checks will always return false.
    return function() {};
  }
}());

/**
 * Checks whether a function is an ES6 Harmony generator.
 *
 * @private
 * @param {Function} fn
 * @returns {boolean}
 */
function isGenerator(fn) {
  return fn instanceof GeneratorConstructor;
}

3 个答案:

答案 0 :(得分:5)

将您的解决方案与其他解决方案相结合,这样就无需全局GeneratorFunction

g instanceof (function*() {}).constructor

答案 1 :(得分:3)

当前ES6草案中的以下图像非常有助于显示生成器函数与其他对象之间的关系:

Figure 2 (Informative) -- Generator Objects Relationships

如果你有g instanceof GeneratorFunction的全局引用,看起来你应该能够使用GeneratorFunction,否则我认为你当前的方法很好。

以下是从V8 unit test file借用的GeneratorFunction和其他相关对象的引用方法:

function* g() { yield 1; }
var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
var GeneratorFunction = GeneratorFunctionPrototype.constructor;
var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;

答案 2 :(得分:0)

判断某件事是否是发电机:

const g = (function*() {yield 1;});
const GeneratorFunctionPrototype = Object.getPrototypeOf(g);

function isGenerator(thing) {
  return typeof thing === 'object' && thing.constructor === GeneratorFunctionPrototype;
}

在原始问题中,这回答isGenerator(gen)为真。 虽然g是生成器函数。当您调用生成器函数时,您将生成一个生成器。

但在大多数情况下,询问事物是否为迭代器更为重要:

function isIterator(thing) {
  // If thing has a Symbol.iterator
  return typeof thing === 'object' && thing[Symbol.iterator];
}

用法:

function *Pseq(list, repeats=1) {
  for (let i = 0; i < repeats; i++) {
    for (let value of list) {
      if (isIterator(value)) {
        yield *value;
      } else {
        yield value;        
      }
    }    
  }
}

let q = Pseq([1, 2, 3, Pseq([10, 20, 30], 2), 4], 2);

for (let v of q) {
  console.log(v);
}

1 2 3 10 20 三十 10 20 三十 4 1 2 3 4

这是迭代序列。如果在该序列中嵌入了迭代器,则在继续序列之前使用yield委托迭代该迭代器。生成器并不是唯一可以产生有用迭代器的东西。