check if function is a generator

2019-01-07 15:50发布

I played with generators in Nodejs v0.11.2 and I'm wondering how I can check that argument to my function is generator function.

I found this way typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function) but I'm not sure if this is good (and working in future) way.

What is your opinion about this issue?

10条回答
Deceive 欺骗
2楼-- · 2019-01-07 16:24

TJ Holowaychuk's co library has the best function for checking whether something is a generator function. Here is the source code:

function isGeneratorFunction(obj) {
   var constructor = obj.constructor;
   if (!constructor) return false;
   if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
   return isGenerator(constructor.prototype);
}

Reference: https://github.com/tj/co/blob/717b043371ba057cb7a4a2a4e47120d598116ed7/index.js#L221

查看更多
劳资没心,怎么记你
3楼-- · 2019-01-07 16:25

As @Erik Arvidsson stated, there is no standard-way to check if a function is a generator function. But you can, for sure, just check for the interface, a generator function fulfills:

function* fibonacci(prevPrev, prev) {

  while (true) {

    let next = prevPrev + prev;

    yield next;

    prevPrev = prev;
    prev = next;
  }
}

// fetch get an instance
let fibonacciGenerator = fibonacci(2, 3)

// check the interface
if (typeof fibonacciGenerator[Symbol.iterator] == 'function' && 
    typeof fibonacciGenerator['next'] == 'function' &&
    typeof fibonacciGenerator['throw'] == 'function') {

  // it's safe to assume the function is a generator function or a shim that behaves like a generator function

  let nextValue = fibonacciGenerator.next().value; // 5
}

Thats's it.

查看更多
一夜七次
4楼-- · 2019-01-07 16:29

A difficulty not addressed on here yet is that if you use the bind method on the generator function, it changes the name its prototype from 'GeneratorFunction' to 'Function'.

There's no neutral Reflect.bind method, but you can get around this by resetting the prototype of the bound operation to that of the original operation.

For example:

const boundOperation = operation.bind(someContext, ...args)
console.log(boundOperation.constructor.name)       // Function
Reflect.setPrototypeOf(boundOperation, operation)
console.log(boundOperation.constructor.name)       // GeneratorFunction
查看更多
The star\"
5楼-- · 2019-01-07 16:32

In the latest version of nodejs (I verified with v0.11.12) you can check if the constructor name is equal to GeneratorFunction. I don't know what version this came out in but it works.

function isGenerator(fn) {
    return fn.constructor.name === 'GeneratorFunction';
}
查看更多
登录 后发表回答