【问题标题】:How to identify an ES6 generator如何识别 ES6 生成器
【发布时间】:2014-02-28 19:52:49
【问题描述】:

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

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

var gen = g();

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

这似乎是一种可能性:

g.constructor.name === 'GeneratorFunction'

有没有更好的办法?

更新:我最终得到了类似于Eric's answertaking an approach,但首先使用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;
}

【问题讨论】:

  • 或者你可以更宽容地使用 typeof gen.next === "function" && typeof gen.throw === "function"
  • 这仅在 fn 实际使用 GeneratorFunction 创建时才有效,对吗?有没有办法确定一个对象是否是从生成器创建的?在 firefox 中 gen['@@iterator'] 似乎已定义,但我无法为节点找出它。我很惊讶迭代器不是从 Iterator 派生的,所以 gen instanceof Iterator 可以工作。

标签: javascript generator ecmascript-harmony


【解决方案1】:

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

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

【讨论】:

  • 很好,这也是我想出的解决方案。除了我什至想处理当前平台不支持生成器的情况(在这种情况下,此解决方案会引发语法错误)。所以我实际上 eval 一个字符串,它应该评估为生成器函数并获取 that 的构造函数;如果它引发错误而不是我返回 false。
  • Generator = (function*() {}).constructor 后跟 g instanceof Generator 更清晰一点。有没有办法判断 g() 是否是生成器的实例,即g() instanceof Iterator
  • @NickSotiros 这不是生成器,而是生成器函数。当被调用时,它会产生一个生成器。
【解决方案2】:

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

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

以下是如何获得对GeneratorFunction 和其他相关对象的引用,这些对象是从V8 unit test file 借来的:

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

【讨论】:

  • 有没有办法判断GeneratorFunctionPrototype 来自哪个生成器?例如,要从给定迭代器来自的同一生成器创建一个新迭代器?
【解决方案3】:

判断某物是否是生成器:

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

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

在最初的问题中,这回答了isGenerator(gen) true。 而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 30 10 20 30 4 1 2 3 4

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-28
    • 2016-07-11
    • 2018-04-14
    • 1970-01-01
    相关资源
    最近更新 更多