我在Nodejs v0.11.2中尝试了生成器(generators),我想知道如何检查传递给我的函数的参数是否是生成器函数。
我发现这种方法 typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function)
,但我不确定这是一个好方法(并且在未来是否有效)。
你对这个问题有什么看法?
我在Nodejs v0.11.2中尝试了生成器(generators),我想知道如何检查传递给我的函数的参数是否是生成器函数。
我发现这种方法 typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(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++;
}
}
这两个行为是相同的(减去 .throw(),但它也可以添加)
Unexpected token [
错误提示在[iterator]: function() {
处。这是怎么回事? - Yanick Rochonvar obj = {}; obj.next = function(){...}; obj[iterator] = () => this;
- Benjamin Gruenbaumnext
和[iterator]
的对象返回,next
返回value
和count
等),来判断它是否为生成器。这样做能够在可预见的未来始终有效吗? - trysisGeneratorFunction
。我不知道这是在哪个版本中推出的,但它有效。function isGenerator(fn) {
return fn.constructor.name === 'GeneratorFunction';
}
const isGenerator = fn => ['GeneratorFunction', 'AsyncGeneratorFunction'].includes(fn.constructor.name)
。异步生成器是 ES2018 的一部分,在 node v10 中可用,参见 node.green。 - tleb这在 node 和 Firefox 中都可以运行:
var GeneratorFunction = (function*(){yield undefined;}).constructor;
function* test() {
yield 1;
yield 2;
}
console.log(test instanceof GeneratorFunction); // true
但是如果你绑定了一个生成器,它就不起作用了,例如:
foo = test.bind(bar);
console.log(foo instanceof GeneratorFunction); // false
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;
Generator = (function*(){}).constructor; g instanceof Generator
,不幸的是 (function*(){}).prototype.constructor
不是检查生成器迭代器的 instanceof 的有效参数。 - Nick Sotiros在 Node 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
在我的测试中,这适用于所有情况。上面的评论说它不适用于命名生成器函数表达式,但我无法复现:
const genExprName=function*name(){};
genExprName instanceof GeneratorFunction; // true
(function*name2(){}) instanceof GeneratorFunction; // true
.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
async function*asgen(){}。
- FerrybigTJ 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);
}
参考:https://github.com/tj/co/blob/717b043371ba057cb7a4a2a4e47120d598116ed7/index.js#L221
这是一个关于it技术的参考链接。请点击上方的链接进行查看。正如 @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
}
这就是它。
function isGenerator(target) {
return target[Symbol.toStringTag] === 'GeneratorFunction';
}
function isGenerator(target) {
return Object.prototype.toString.call(target) === '[object GeneratorFunction]';
}
传统的方法Object.prototype.toString.call(val)
也可以使用。在Node版本11.12.0中,它返回[object Generator]
,但是最新版的Chrome和Firefox返回[object GeneratorFunction]
。
因此,可能会像这样:
function isGenerator(val) {
return /\[object Generator|GeneratorFunction\]/.test(Object.prototype.toString.call(val));
}
我查看了一下 koa 是如何做到的,他们使用了这个库:https://github.com/ljharb/is-generator-function。
你可以像这样使用它:
const isGeneratorFunction = require('is-generator-function');
if(isGeneratorFunction(f)) {
...
}
f instanceof GeneratorFunction
应该可以工作。 - user1106925