5

假设我有一个像这样的生成器函数:

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

var gen = g();

我如何以编程方式告诉这g是一个生成器函数,或者gen一个迭代器?

这似乎是一种可能性:

g.constructor.name === 'GeneratorFunction'

有没有更好的办法?

更新:我最终采用了类似于Eric 的回答的方法,但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;
}
4

3 回答 3

5

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

图 2(信息性)——生成器对象关系

g instanceof GeneratorFunction因此,如果您对 有全局引用,看起来您应该可以使用GeneratorFunction,否则我认为您当前的方法很好。

以下是从V8 单元测试文件GeneratorFunction中借用的引用和其他相关对象的方法:

function* g() { yield 1; }
var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
var GeneratorFunction = GeneratorFunctionPrototype.constructor;
var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
于 2014-02-04T17:46:03.220 回答
5

将您的解决方案与其他解决方案相结合,这避免了对全局的需要GeneratorFunction

g instanceof (function*() {}).constructor
于 2014-02-04T17:50:04.580 回答
1

判断某物是否是生成器:

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

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

在最初的问题中,这回答isGenerator(gen)正确。Whileg是一个生成器函数。当您调用生成器函数时,您会生成一个生成器。

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

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 30 10 20 30 4 1 2 3 4

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

于 2016-11-11T11:23:37.517 回答