javascript 检查函数是否是生成器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16754956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 05:52:03  来源:igfitidea点击:

check if function is a generator

javascriptgeneratoryieldecmascript-6

提问by Dima Vidmich

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.

我在 Nodejs v0.11.2 中使用了生成器,我想知道如何检查我的函数的参数是生成器函数。

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.

我找到了这种方式,typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function)但我不确定这是否是好的(并在未来工作)方式。

What is your opinion about this issue?

您对这个问题有什么看法?

采纳答案by Erik Arvidsson

We talked about this in the TC39 face-to-face meetings and it is deliberate that we don't expose a way to detect whether a function is a generator or not. The reason is that any function can return an iterable object so it does not matter if it is a function or a generator function.

我们在 TC39 面对面会议中讨论过这个问题,并且故意不公开检测函数是否为生成器的方法。原因是任何函数都可以返回一个可迭代对象,所以它是函数还是生成器函数都没有关系。

var iterator = Symbol.iterator;

function notAGenerator() {
  var  count = 0;
  return {
    [iterator]: function() {
      return this;
    },
    next: function() {
      return {value: count++, done: false};
    }
  }
}

function* aGenerator() {
  var count = 0;
  while (true) {
    yield count++;
  }
}

These two behave identical (minus .throw() but that can be added too)

这两个行为相同(减去 .throw() 但也可以添加)

回答by smitt04

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.

在最新版本的 nodejs(我用 v0.11.12 验证过)中,您可以检查构造函数名称是否等于GeneratorFunction. 我不知道这是什么版本,但它有效。

function isGenerator(fn) {
    return fn.constructor.name === 'GeneratorFunction';
}

回答by Nick Sotiros

this works in node and in firefox:

这适用于节点和火狐:

var GeneratorFunction = (function*(){yield undefined;}).constructor;

function* test() {
   yield 1;
   yield 2;
}

console.log(test instanceof GeneratorFunction); // true

jsfiddle

提琴手

But it does not work if you bind a generator, for example:

但是如果你绑定一个生成器,它就不起作用,例如:

foo = test.bind(bar); 
console.log(foo instanceof GeneratorFunction); // false

回答by Albert

I'm using this:

我正在使用这个:

var sampleGenerator = function*() {};

function isGenerator(arg) {
    return arg.constructor === sampleGenerator.constructor;
}
exports.isGenerator = isGenerator;

function isGeneratorIterator(arg) {
    return arg.constructor === sampleGenerator.prototype.constructor;
}
exports.isGeneratorIterator = isGeneratorIterator;

回答by freddyrangel

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

TJ Holowaychuk 的co库具有检查某事物是否是生成器函数的最佳功能。这是源代码:

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

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

回答by freddyrangel

In node 7 you can instanceofagainst the constructors to detect both generator functions and async functions:

在节点 7 中,您可以instanceof针对构造函数来检测生成器函数和异步函数:

const GeneratorFunction = function*(){}.constructor;
const AsyncFunction = async function(){}.constructor;

function norm(){}
function*gen(){}
async function as(){}

norm instanceof Function;              // true
norm instanceof GeneratorFunction;     // false
norm instanceof AsyncFunction;         // false

gen instanceof Function;               // true
gen instanceof GeneratorFunction;      // true
gen instanceof AsyncFunction;          // false

as instanceof Function;                // true
as instanceof GeneratorFunction;       // false
as instanceof AsyncFunction;           // true

This works for all circumstances in my tests. A comment above says it doesn't work for named generator function expressions but I'm unable to reproduce:

这适用于我的测试中的所有情况。上面的评论说它不适用于命名生成器函数表达式,但我无法重现:

const genExprName=function*name(){};
genExprName instanceof GeneratorFunction;            // true
(function*name2(){}) instanceof GeneratorFunction;   // true

The only problem is the .constructorproperty of instances can be changed. If someone was really determined to cause you problems they could break it:

唯一的问题是.constructor实例的属性可以更改。如果有人真的决心给你带来麻烦,他们可能会破坏它:

// Bad people doing bad things
const genProto = function*(){}.constructor.prototype;
Object.defineProperty(genProto,'constructor',{value:Boolean});

// .. sometime later, we have no access to GeneratorFunction
const GeneratorFunction = function*(){}.constructor;
GeneratorFunction;                     // [Function: Boolean]
function*gen(){}
gen instanceof GeneratorFunction;      // false

回答by kyr0

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:

正如@Erik Arvidsson 所说,没有标准方法可以检查函数是否是生成器函数。但是你可以肯定的是,只需检查接口,一个生成器函数就可以满足:

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.

就是这样。

回答by Mario ?krlec

The old school Object.prototype.toString.call(val)seems to work also. In Node version 11.12.0 it returns [object Generator]but latest Chrome and Firefox return [object GeneratorFunction].

旧学校Object.prototype.toString.call(val)似乎也有效。在 Node 版本 11.12.0 中,它返回[object Generator]但最新的 Chrome 和 Firefox 返回[object GeneratorFunction]

So could be like this:

所以可能是这样的:

function isGenerator(val) {
    return /\[object Generator|GeneratorFunction\]/.test(Object.prototype.toString.call(val));

}

回答by Lex

Mozilla javascript documentation describes Function.prototype.isGeneratormethod MDN API. Nodejs does not seem to implement it. However if you are willing to limit your code to defining generators with function*only (no returning iterable objects) you can augment it by adding it yourself with a forward compatibility check:

Mozilla javascript 文档描述了MDN APIFunction.prototype.isGenerator方法。Nodejs 似乎没有实现它。但是,如果您愿意将代码限制为仅使用(不返回可迭代对象)定义生成器,您可以通过向前兼容性检查自己添加它来增强它:function*

if (typeof Function.prototype.isGenerator == 'undefined') {
    Function.prototype.isGenerator = function() {
        return /^function\s*\*/.test(this.toString());
    }
}

回答by kraf

I checked how koadoes it and they use this library: https://github.com/ljharb/is-generator-function.

我检查了koa是如何做到的,他们使用了这个库:https: //github.com/ljharb/is-generator-function

You can use it like this

你可以像这样使用它

const isGeneratorFunction = require('is-generator-function');
if(isGeneratorFunction(f)) {
    ...
}