праверыць, калі функцыя генератар

Я гуляў з генератарамі 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.

Якое Ваша меркаванне па гэтым пытанні?

45
@Funkodebat: Вы блытаеце вяртаецца значэнне (итератор) з механізмам стварэння вяртаецца значэння (функцыі генератара супраць любога з некалькіх іншых спосабаў стварэння итераторов вы можаце вярнуцца з функцыі без генератара). І будучы неканструктыўнай з «FanBoy» нонсэнсам. Я сапраўды павінен <�б> не сказаў, што «проста функцыя, якая вяртае итератор» вышэй, аднак, што гэта няправільна, і я выдаліў яго. Але кропка Эрыка застаецца ў сіле: Там няма нічога карыснага вы можаце зрабіць з інфармацыяй, акрамя сказаць: "Так, гэта функцыя генератара.»
дададзена аўтар T.J. Crowder, крыніца
Паколькі пытанне канкрэтна да вузла v0.11.2, я не ведаю адказу. Тым не менш, усё больш нядаўніх версіі могуць рабіць добра (таксама, калі ацэнка) stackoverflow.com/questions/26769593/… </а >
дададзена аўтар niry, крыніца
Там павінна быць нешта !!! генератар адрозніваецца ад функцыі ..
дададзена аўтар Funkodebat, крыніца
ня @ T.J.Crowder калі не адрозніваецца, то не павінна быць ніякай розніцы пры аб'яўленні іх, ад ідэальнай пункту гледжання, хоць гэта было б вельмі сумна для першапачатковага выпуску, калі яны рэалізуюць тое, што патрабуе змены ў дэкларацыі, але не значнай розніцы пасля гэтага. Я не спрачаюся, таму што практыка часта не ідэальная, але няма ні аднаго аргументу, акрамя таго, каб быць Fanboy, што вы можаце зрабіць, каб сказаць, што гэта не павінна мець магчымасць счытваць значэнне, калі розніца ён павінен аб'явіць. Таму, калі ласка, не будзьце Fanboy.
дададзена аўтар Funkodebat, крыніца
Гэты канструктар па-відаць, новае дадатак да самай апошняй версіі праекта. Пошук папярэдняй, я не лічу, што тэкст. Калі выказаць здагадку, што ён застаецца ў спецыфікацыі, я выказаў здагадку бы, што было б паказаць, у нейкі момант. <�Я> EDIT: </я> ... ах да, я бачу гэта ў заўвагах змены <�я> «Дададзена семантыка для функцыі генератара і генератара азначэнняў метаду» ... так падобна, што толькі што прызямліўся каля 10 дзён таму.
дададзена аўтар user1106925, крыніца
Упэўнены, е InstanceOf GeneratorFunction павінен працаваць, грунтуючыся на <�я> 15.19.3.1 GeneratorFunction Канструктар з бягучага праекта ES6.
дададзена аўтар user1106925, крыніца
nodejs v0.11.2 ня GeneratorFunction, так што я думаю, што v8 v3.19.0 не мае яго таксама. але так, гэтая праверка будзе нашмат прасцей.
дададзена аўтар Dima Vidmich, крыніца
Я бачу гэта змяненне было выдаленае з v8 з-за некаторых тэставых задач github.com/v8/v8/commit/& hellip;
дададзена аўтар Dima Vidmich, крыніца

10 адказы

У апошняй версіі nodejs (я праверыў з v0.11.12) вы можаце праверыць, калі імя канструктара роўна GeneratorFunction . Я не ведаю, якая версія гэта выйшла ў Расеі, але гэта працуе.

function isGenerator(fn) {
    return fn.constructor.name === 'GeneratorFunction';
}
37
дададзена
Гэта працуе толькі з аб'явай функцый і ананімнымі функцыямі, ён не працуе з найменных функцыянальнымі выразамі.
дададзена аўтар trysis, крыніца
«Вы можаце выкарыстоўваць obj.constructor.name праверыць" клас "аб'екта» developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , хоць і з агаворкамі, см stackoverflow.com/questions/29310530/…
дададзена аўтар user5321531, крыніца
Выдатнае рашэнне, дзякуй! Абнаўленне для сучаснага JS :. <�Код> Вуснаў isGenerator = п => [ 'GeneratorFunction', 'AsyncGeneratorFunction'] ўключае ў сябе (fn.constructor.name) . Async генератары з'яўляюцца часткай ES2018, даступныя ў вузле v10 см node.green </а>
дададзена аўтар tleb, крыніца

Мы гаварылі пра гэта на сустрэчах 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 (), але якія могуць быць дададзеныя таксама)

31
дададзена
Я павінен адзначыць, што, нават з самай апошняй версіяй Dev з Node.js, гэты фрагмент кода не працуе, і я атрымліваю Нечаканы маркер [ у [итератора]: функцыя() {. Адкуль гэта ўзялося?
дададзена аўтар Yanick Rochon, крыніца
@YanickRochon гэта новы аб'ект натацыі, вы можаце пабудаваць аб'ект і выкарыстоўваць кранштэйны абазначэнні - гэта значыць вар OBJ = {}; obj.next = функцыя() {...}; OBJ [итератор] =() => гэта
дададзена аўтар Benjamin Gruenbaum, крыніца
@Erik Наконт з асінхроннымі функцыямі. Тыя адкласці рэчы пасля цікаў, так што я думаю, што гэта можа мець сэнс, каб ведаць, калі мы маем асінхроннай функцыі або няма ў пэўных выпадках. Проста таму, што любая функцыя можа вяртаць Promise не значыць, што мы не павінны быць у стане сказаць, розніцу.
дададзена аўтар trusktr, крыніца
Дарэчы, нічога сабе, што на самой справе ўсё, што аддзяляе функцыю ад функцыі генератара, ці гэта проста спрошчаная карціна?
дададзена аўтар trysis, крыніца
@Erik, Дык вы кажаце, функцыя генератара толькі спецыяльны клас функцыі, а не нешта іншае? Тады, магчыма, мы можам убачыць, калі функцыя з'яўляецца генератар, праверыўшы, што ён мае ўсе характарыстыкі генератара (вяртае аб'ект, які змяшчае Далей і [итератора] , Наступны вяртае значэнне і Колькасць і г.д.) Ці будзе гэта паслядоўна працаваць у агляднай будучыні?
дададзена аўтар trysis, крыніца
@LexPodgorny Там на самай справе, здаецца, значна больш, калі вы Google «ES6 Сімвалы». Раней яны былі вядомыя як Імёны . Акрамя таго, лепш рэсурс тут
дададзена аўтар Some Guy, крыніца
@LexPodgorny я знайшоў вельмі мала згадак пра Symbol, тут , тут і тут
дададзена аўтар Some Guy, крыніца
Нічога сабе ... занадта дрэнна :( Ня здольнасць вызначыць гэта функцыя генератара або простая функцыя не дазволіць прыемныя рэчы, як інтэграцыя з primise бібліятэк (напрыклад, Q.async) для аўтаматычнага выяўлення генератараў і FETCH/націскныя значэння там, каб мець добры і чысты «primise» АПА на аснове генератараў.
дададзена аўтар Valentyn Shybanov, крыніца
@Erik Арвідсан Дзе мы маглі б знайсці дакументацыю для функцыі Symbol?
дададзена аўтар Division by Zero, крыніца
Перафразуючы гэты адказ: генератар ўяўляе сабой функцыю, якая вяртае итератор.
дададзена аўтар cdosborn, крыніца

Я выкарыстоўваю гэта:

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;
9
дададзена
Я скараціць гэта Generator = (функцыя *() {}) Канструктар .; г InstanceOf генератара , Unfortunatly (функцыя *() {}). prototype.constructor не з'яўляецца дапушчальным параметрам InstanceOf для праверкі итераторы генератара
дададзена аўтар Nick Sotiros, крыніца

TJ 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);
}

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

6
дададзена

гэта працуе ў вузле і ў браўзэры Firefox:

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

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

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

jsfiddle

Але гэта не працуе, калі вы зьвяжаце генератар, напрыклад:

foo = test.bind(bar); 
console.log(foo instanceof GeneratorFunction);//false
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

Гэта працуе для ўсіх выпадкаў у маіх тэстах. Каментар вышэй кажа, што гэта не працуе для найменных выразаў функцыі генератара, але я не ў стане прайграць:

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
4
дададзена
Гэты адказ не працуе, калі вы выкарыстоўваеце функцыю асінхроннага генератара, толькі 1 дакладна вяртаюцца: функцыя асінхроннай * asgen() {}
дададзена аўтар Ferrybig, крыніца
Працаваў для мяне. Вялікае мысленне! Вядома, заўсёды ёсць адказ Нік Sotiros ', 2 гады да вас.
дададзена аўтар MasterBob, крыніца

Mozilla Javascript дакументацыя апісвае Function.prototype.isGenerator метад MDN API . Nodejs не здаецца, рэалізаваць яго. Аднак, калі вы гатовыя абмежаваць свой код вызначэння генератараў з функцыі * толькі (без вяртання ітэрацыю аб'ектаў), вы можаце павялічыць яго, дадаўшы яго самастойна з праверкай прамой сумяшчальнасці:

if (typeof Function.prototype.isGenerator == 'undefined') {
    Function.prototype.isGenerator = function() {
        return /^function\s*\*/.test(this.toString());
    }
}
2
дададзена
Вы можаце разгледзець прабелы, якія маглі б быць там. <�Код> функцыя * (Арг) {} або функцыя * (Арг) {} Я бачыў абодвух. Я не здзіўлюся, калі вузел дададзены дэтэктар першапачаткова, таму што ToString занадта дорага
дададзена аўтар Funkodebat, крыніца

Як паказана @Erik Арвідсан, няма стандартнага спосабу праверыць, калі функцыя з'яўляецца функцыяй генератара. Але вы можаце, вядома, проста праверыць інтэрфейс, функцыя генератара выконвае:

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
}

Вось і ўсё.

2
дададзена
Я б праверыў fn.constructor.name , але так як функцыя была перададзена Паўсюдна ў Proxy ён паведаміў пра гэта як рэгулярная функцыя ... так што я павінен быў рабіць тое, што вы прапанавалі і прымяніць сопрограмму пасля
дададзена аўтар Endless, крыніца

Я праверыў, як Коа робіць гэта, і яны выкарыстоўваюць гэтую бібліятэку: https://github.com/ljharb/is-generator-function .

Вы можаце выкарыстоўваць яго, як гэта

const isGeneratorFunction = require('is-generator-function');
if(isGeneratorFunction(f)) {
    ...
}
1
дададзена
Я дадаць радок кода, каб прадэманстраваць карыснасць бібліятэкі, але я да гэтага часу думаю, згадаць шматразовы бібліятэку, якая вырашае пастаўленую задачу, мае сэнс тут.
дададзена аўтар kraf, крыніца

Цяжкасць не разглядаецца тут яшчэ ў тым, што калі вы выкарыстоўваеце прывязкі метад на функцыі генератара, ён змяняе імя яго прататып з «GeneratorFunction» да «Function».

Там няма нейтральнага Reflect.bind метаду, але вы можаце абыйсці гэта шляхам скіду прататыпа звязаных аперацый, што ў першапачатковай аперацыі.

Напрыклад:

const boundOperation = operation.bind(someContext, ...args)
console.log(boundOperation.constructor.name)      //Function
Reflect.setPrototypeOf(boundOperation, operation)
console.log(boundOperation.constructor.name)      //GeneratorFunction
0
дададзена