tutorial soljson smart remix org optimize false español curso aprender 59dbf8f1 javascript generator yield ecmascript-6

javascript - soljson - solidity español



verificar si la función es un generador (10)

Jugué con generadores en Nodejs v0.11.2 y me pregunto cómo puedo verificar ese argumento para que mi función sea la función de generador.

Encontré de esta forma typeof f === ''function'' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function) pero no estoy seguro de si esto es bueno (y funciona en el futuro).

¿Cuál es tu opinión sobre este tema?


La documentación de Mozilla javascript describe el método Function.prototype.isGenerator MDN API . Nodejs no parece implementarlo. Sin embargo, si está dispuesto a limitar su código para definir generadores con function* solamente (sin devolver objetos iterables), puede aumentarlo agregándolo usted mismo con una verificación de compatibilidad futura:

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


Estoy usando esto:

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;


En la última versión de nodejs (verifiqué con v0.11.12) puedes verificar si el nombre del constructor es igual a GeneratorFunction . No sé en qué versión salió esto, pero funciona.

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


La biblioteca de co TJ Holowaychuk tiene la mejor función para verificar si algo es una función del generador. Aquí está el código fuente:

function isGeneratorFunction(obj) { var constructor = obj.constructor; if (!constructor) return false; if (''GeneratorFunction'' === constructor.name || ''GeneratorFunction'' === constructor.displayName) return true; return isGenerator(constructor.prototype); }

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


Hablamos de esto en las reuniones cara a cara de TC39 y es deliberado que no exponemos una forma de detectar si una función es un generador o no. La razón es que cualquier función puede devolver un objeto iterable, por lo que no importa si se trata de una función o una función del generador.

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++; } }

Estos dos se comportan de manera idéntica (menos .throw () pero eso se puede agregar también)


En el nodo 7 puedes instanceof contra los constructores para detectar tanto funciones del generador como funciones asíncronas:

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

Esto funciona para todas las circunstancias en mis pruebas. Un comentario anterior dice que no funciona para expresiones de funciones de generador con nombre, pero no puedo reproducir:

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

El único problema es que la propiedad .constructor de instancias se puede cambiar. Si alguien estaba realmente decidido a causarte problemas, podrían romperlo:

// 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


Una dificultad no abordada aquí todavía es que si usa el método bind en la función del generador, cambia el nombre de su prototipo de ''GeneratorFunction'' a ''Function''.

No hay un método neutral Reflect.bind , pero puede evitar esto restableciendo el prototipo de la operación vinculada a la de la operación original.

Por ejemplo:

const boundOperation = operation.bind(someContext, ...args) console.log(boundOperation.constructor.name) // Function Reflect.setPrototypeOf(boundOperation, operation) console.log(boundOperation.constructor.name) // GeneratorFunction


Como dijo @Erik Arvidsson, no hay una forma estándar de verificar si una función es una función de generador. Pero puedes estar seguro de que solo verificas la interfaz, una función del generador cumple:

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 }

Eso es todo.



esto funciona en node y en firefox:

var GeneratorFunction = (function*(){yield undefined;}).constructor; function* test() { yield 1; yield 2; } console.log(test instanceof GeneratorFunction); // true

jsfiddle

Pero no funciona si enlaza un generador, por ejemplo:

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