Dim*_*ich 54 javascript yield generator ecmascript-6
我在Nodejs v0.11.2中使用了生成器,我想知道如何检查我的函数的参数是生成器函数.
我找到了这种方式,typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function)但我不确定这是否好(并在将来工作)方式.
你对这个问题有什么看法?
smi*_*t04 43
在nodejs的最新版本中(我使用v0.11.12验证),您可以检查构造函数名称是否等于GeneratorFunction.我不知道它出现了什么版本,但它有效.
function isGenerator(fn) {
return fn.constructor.name === 'GeneratorFunction';
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*son 39
我们在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++;
}
}
Run Code Online (Sandbox Code Playgroud)
这两个表现相同(减去.throw(),但也可以添加)
Nic*_*ros 10
这适用于节点和firefox:
var GeneratorFunction = (function*(){yield undefined;}).constructor;
function* test() {
yield 1;
yield 2;
}
console.log(test instanceof GeneratorFunction); // true
Run Code Online (Sandbox Code Playgroud)
但是如果绑定生成器它不起作用,例如:
foo = test.bind(bar);
console.log(foo instanceof GeneratorFunction); // false
Run Code Online (Sandbox Code Playgroud)
我正在使用这个:
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;
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
参考:https://github.com/tj/co/blob/717b043371ba057cb7a4a2a4e47120d598116ed7/index.js#L221
小智 6
在节点 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
Run Code Online (Sandbox Code Playgroud)
这适用于我的测试中的所有情况。上面的评论说它不适用于命名生成器函数表达式,但我无法重现:
const genExprName=function*name(){};
genExprName instanceof GeneratorFunction; // true
(function*name2(){}) instanceof GeneratorFunction; // true
Run Code Online (Sandbox Code Playgroud)
唯一的问题是.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
Run Code Online (Sandbox Code Playgroud)
正如@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
}
Run Code Online (Sandbox Code Playgroud)
就是这样。