site - telecharger code javascript gratuit




vérifier si la fonction est un générateur (7)

La documentation de Mozilla javascript décrit Function.prototype.isGenerator API MDN de la méthode Function.prototype.isGenerator . Nodejs ne semble pas l'implémenter. Toutefois, si vous souhaitez limiter votre code à la définition de générateurs avec la function* uniquement (pas de renvoi d'objets iterables), vous pouvez l'augmenter en l'ajoutant vous-même avec une vérification de compatibilité en aval:

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

J'ai joué avec des générateurs dans Nodejs v0.11.2 et je me demande comment je peux vérifier cet argument à ma fonction est la fonction de générateur.

J'ai trouvé cette façon typeof f === 'function' && Object.getPrototypeOf(f) !== Object.getPrototypeOf(Function) mais je ne suis pas sûr que ce soit bon (et fonctionne dans le futur).

Quelle est votre opinion sur ce problème?


J'utilise ceci:

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;

La bibliothèque de TJ Holowaychuk a la meilleure fonction pour vérifier si quelque chose est une fonction de générateur. Voici le code source:

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

Référence: https://github.com/tj/co/blob/717b043371ba057cb7a4a2a4e47120d598116ed7/index.js#L221


Nous en avons parlé dans les réunions face à face du TC39 et il est délibéré de ne pas exposer un moyen de détecter si une fonction est un générateur ou non. La raison en est que n'importe quelle fonction peut renvoyer un objet itérable de sorte que cela n'a pas d'importance s'il s'agit d'une fonction ou d'une fonction de générateur.

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

Ces deux se comportent de manière identique (moins .throw () mais cela peut aussi être ajouté)


Une difficulté non abordée ici est que si vous utilisez la méthode bind sur la fonction de générateur, elle change le nom de son prototype de 'GeneratorFunction' à 'Function'.

Il n'existe pas de méthode Reflect.bind neutre, mais vous pouvez contourner ce Reflect.bind en réinitialisant le prototype de l'opération liée à celui de l'opération d'origine.

Par exemple:

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

Comme l'a déclaré @Erik Arvidsson, il n'existe pas de méthode standard pour vérifier si une fonction est une fonction de générateur. Mais vous pouvez, à coup sûr, vérifier simplement l'interface, une fonction de générateur remplit:

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
}

C'est ça.


cela fonctionne dans le noeud et dans firefox:

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

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

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

jsfiddle

Mais cela ne fonctionne pas si vous liez un générateur, par exemple:

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




ecmascript-6