119 votes

Ajout automatique de console.log à chaque fonction

Existe-t-il un moyen de faire en sorte que n'importe quelle fonction produise une déclaration console.log lorsqu'elle est appelée, en enregistrant un hook global quelque part (c'est-à-dire sans modifier la fonction elle-même) ou par un autre moyen ?

1 votes

Excellente question, j'aimerais bien savoir si c'est possible mais je suis presque sûr que non... Peut-être ajouter une demande de fonctionnalité pour que cela soit ajouté dans le moteur de js de votre navigateur préféré ? :-)

0 votes

Question parfaite, j'ai besoin de quelque chose de similaire à ceci

71voto

lwburk Points 29313

Voici un moyen d'augmenter toutes les fonctions de l'espace de noms global avec la fonction de votre choix :

function augment(withFn) {
    var name, fn;
    for (name in window) {
        fn = window[name];
        if (typeof fn === 'function') {
            window[name] = (function(name, fn) {
                var args = arguments;
                return function() {
                    withFn.apply(this, args);
                    return fn.apply(this, arguments);

                }
            })(name, fn);
        }
    }
}

augment(function(name, fn) {
    console.log("calling " + name);
});

L'inconvénient est qu'aucune fonction créée après l'appel à augment aura le comportement supplémentaire.

0 votes

Traite-t-il correctement les valeurs de retour de la fonction ?

2 votes

@SunnyShah Non, ça ne l'est pas : jsfiddle.net/Shawn/WnJQ5 Mais celui-là, oui : jsfiddle.net/Shawn/WnJQ5/1 bien que je ne sois pas sûr que cela fonctionne dans TOUS les cas... La différence est de changer fn.apply(this, arguments); à return fn.apply(this, arguments);

2 votes

@Shawn @SunnyShah Corrigé. J'avais juste besoin d'ajouter un return à la fonction la plus interne.

25voto

Sergey Mell Points 754

Pour moi, cela semble être la solution la plus élégante :

(function() {
    var call = Function.prototype.call;
    Function.prototype.call = function() {
        console.log(this, arguments); // Here you can do whatever actions you want
        return call.apply(this, arguments);
    };
}());

11voto

Soorena Points 1167

Méthode Proxy pour enregistrer les appels de fonction

Il existe une nouvelle façon d'utiliser Proxy pour réaliser cette fonctionnalité en JS. Supposons que nous voulions avoir un console.log chaque fois qu'une fonction d'une classe spécifique est appelée :

class TestClass {
  a() {
    this.aa = 1;
  }
  b() {
    this.bb = 1;
  }
}

const foo = new TestClass()
foo.a() // nothing get logged

nous pouvons remplacer notre instanciation de classe par un Proxy qui surcharge chaque propriété de cette classe. ainsi :

class TestClass {
  a() {
    this.aa = 1;
  }
  b() {
    this.bb = 1;
  }
}

const logger = className => {
  return new Proxy(new className(), {
    get: function(target, name, receiver) {
      if (!target.hasOwnProperty(name)) {
        if (typeof target[name] === "function") {
          console.log(
            "Calling Method : ",
            name,
            "|| on : ",
            target.constructor.name
          );
        }
        return new Proxy(target[name], this);
      }
      return Reflect.get(target, name, receiver);
    }
  });
};

const instance = logger(TestClass)

instance.a() // output: "Calling Method : a || on : TestClass"

vérifier que cela fonctionne réellement dans le Codepen


N'oubliez pas que l'utilisation de Proxy vous offre beaucoup plus de fonctionnalités que la simple consignation des noms de la console.

Cette méthode fonctionne également dans Node.js aussi.

0 votes

Est-il possible de le faire sans utiliser les instances et les classes ? En particulier dans node.js ?

0 votes

@Revadike cela devrait aider : stackoverflow.com/a/28708700/5284370

2voto

Peter Tseng Points 3272

Si vous souhaitez une consignation plus ciblée, le code suivant consignera les appels de fonction pour un objet particulier. Vous pouvez même modifier les prototypes d'objets pour que toutes les nouvelles instances soient également journalisées. J'ai utilisé Object.getOwnPropertyNames au lieu de for...in, pour que cela fonctionne avec les classes ECMAScript 6, qui n'ont pas de méthodes énumérables.

function inject(obj, beforeFn) {
    for (let propName of Object.getOwnPropertyNames(obj)) {
        let prop = obj[propName];
        if (Object.prototype.toString.call(prop) === '[object Function]') {
            obj[propName] = (function(fnName) {
                return function() {
                    beforeFn.call(this, fnName, arguments);
                    return prop.apply(this, arguments);
                }
            })(propName);
        }
    }
}

function logFnCall(name, args) {
    let s = name + '(';
    for (let i = 0; i < args.length; i++) {
        if (i > 0)
            s += ', ';
        s += String(args[i]);
    }
    s += ')';
    console.log(s);
}

inject(Foo.prototype, logFnCall);

0voto

Martin Jespersen Points 13702

Je ne pense pas qu'il existe un raccourci facile pour cela.

Si vous en avez besoin à des fins de profilage/débogage, vous pouvez peut-être utiliser dynatrace ajax edition (ne fonctionne que pour ie, désolé) qui vous donnera une grande ventilation de ce qui est appelé quand, dans quel ordre, combien de cpu il utilise, et il vous dira même combien de temps passé et quand sur le moteur de rendu interne des navigateurs et autres.

D'une autre manière, si vous n'en avez pas besoin dans un environnement réel, vous pouvez essayer de parcourir récursivement l'espace de noms global et envelopper chaque fonction que vous rencontrez avec quelque chose comme ce code (pseudo, juste pour inspirer, pas pour poursuivre directement) :

function wrap(o) {

  for(var i in o) {
    switch(typeof o[i]) {
      case 'function':
        (function(){
          var fn = o[i];
          o[i] = function() { console.log('whatever'); fn(); }
        })();
        break;
      case 'object':
        wrap(o[i]);
        break; 
    }
  }
}

Je ne peux pas vous dire si cela fonctionnera et/ou si c'est une bonne idée... je ne suis pas sûr que je le ferais, mais je pense que cela pourrait être amusant d'essayer ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X