Я играл с генераторами в Nodejs версии v0.11.2 и я'м интересно как я могу проверить, что аргумент функции является функция генератора.
Я нашел этот путь `Ф вызова typeof === 'функция' &&усилителя; объект.getPrototypeOf(Ф) !== Объект.getPrototypeOf () функция, но я'м не уверен, если это хороший (и работать в будущем) путем.
Каково Ваше мнение об этой проблеме?
В последней версии nodejs (я проверил с v0.11.12) можно проверить, если имя конструктора равна GeneratorFunction
. Я не'т знаю, что это вышло, но он работает.
function isGenerator(fn) {
return fn.constructor.name === 'GeneratorFunction';
}
Мы говорили об этом в 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++;
}
}
Эти двое ведут себя идентично (минус .бросать (), но которые могут быть добавлены)
это работает в узле и в Firefox:
var GeneratorFunction = (function*(){yield undefined;}).constructor;
function* test() {
yield 1;
yield 2;
}
console.log(test instanceof GeneratorFunction); // true
[jsfiddle][1]
Но это не работает, если вы свяжете генератора, например:
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;
ТиДжей Holowaychuk'библиотека с Колорадо
имеет самую лучшую функцию для проверки, является ли что-функциональный генератор. Вот исходный код:
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
В узле 7 Вы можете экземпляром
против конструкторов для обнаружения как функции генератора и асинхронных функций:
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
Это работает для всех обстоятельств в моих тестах. Комментарий выше говорит, что это не't работа для именованную функцию генератора выражения, но я'м не в состоянии воспроизвести:
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
Как @Эрик Арвидсон заявил, что нет стандартного-способ проверить, если функция представляет собой функцию генератора. Но вы можете, конечно, просто проверить для интерфейса, функцию генератора выполняет:
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
}
Это'с его.
В Mozilla JavaScript в документ описывает функции.прототип.isGenerator метод [МДН по API][1]. Nodejs не похоже, чтобы это реализовать. Однако если вы не готовы ограничить свой код для определения генераторы с функцией*
(без возвращения итерируемые объекты) можно расширить, добавив его себя вперед проверка совместимости:
if (typeof Function.prototype.isGenerator == 'undefined') {
Function.prototype.isGenerator = function() {
return /^function\s*\*/.test(this.toString());
}
}
Я проверил, как КоА это делает и они используют эту библиотеку: https://github.com/ljharb/is-generator-function.
Вы можете использовать его, как это
const isGeneratorFunction = require('is-generator-function');
if(isGeneratorFunction(f)) {
...
}
Объект старой школы.прототип.метод toString.вызов(Вэл)
, кажется, работает также. В узле версии 11.12.0 она возвращает[объект генератор]но последний хром и вернуться в Firefox
[объект GeneratorFunction]`.
Так может быть такой:
function isGenerator(val) {
return /\[object Generator|GeneratorFunction\]/.test(Object.prototype.toString.call(val));
}
Трудности еще не решены здесь заключается в том, что если вы используете метод "привязка" на функцию генератора, он меняет имя своего прототипа из 'GeneratorFunction' до 'функция'.
Там's нет нейтральных отражают.привязать метод, но вы можете обойти это путем сброса прототип граница эксплуатации в эксплуатации.
Например:
const boundOperation = operation.bind(someContext, ...args)
console.log(boundOperation.constructor.name) // Function
Reflect.setPrototypeOf(boundOperation, operation)
console.log(boundOperation.constructor.name) // GeneratorFunction