Ajout automatique de console.log à chaque fonction

97

Existe-t-il un moyen de faire en sorte qu'une fonction génère une instruction 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 via un autre moyen?

JRL
la source
excellente question, j'aimerais savoir si cela est possible mais je suis sûr que ce n'est pas le cas ... Peut-être ajouter une demande de fonctionnalité pour qu'elle soit ajoutée dans le moteur js de votre navigateur préféré? :-)
Endophage
Question parfaite, j'ai besoin de quelque chose de similaire comme ça
mjimcua

Réponses:

62

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

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

Wayne
la source
Gère-t-il correctement les valeurs de retour de la fonction?
SunnyShah
2
@SunnyShah Non, ce n'est pas le cas: jsfiddle.net/Shawn/WnJQ5 Mais celui-ci le fait: jsfiddle.net/Shawn/WnJQ5/1 bien que je ne sois pas sûr que cela fonctionnera dans TOUS les cas ... La différence change fn.apply(this, arguments);enreturn fn.apply(this, arguments);
Shawn
2
@Shawn @SunnyShah Fixe. Juste besoin d'ajouter un returnà la fonction la plus profonde.
Wayne
fonctionne presque bien mais j'obtiens une erreur avec cette jquery: call: if (jQuery.isFunction (lSrc)) et il dit: TypeError: jQuery.isFunction n'est pas une fonction
fekiri malek
4
Cette solution n'utilise pas jQuery
Wayne
8

Quant à moi, cela ressemble à 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);
    };
}());
Sergey Mell
la source
7

Méthode proxy pour enregistrer les appels de fonction

Il existe une nouvelle façon d'utiliser Proxy pour obtenir cette fonctionnalité dans JS. supposons que nous voulons avoir une console.logchaque 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 remplace chaque propriété de cette classe. alors:

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 Codepen


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

De plus , cette méthode fonctionne en Node.js aussi.

Soorena
la source
Pouvez-vous également faire cela sans utiliser d'instances et de classes? Plus précisément dans node.js?
Revadike
@Revadike cela devrait aider: stackoverflow.com/a/28708700/5284370
Soorena
1

Si vous souhaitez une journalisation plus ciblée, le code suivant consignera les appels de fonction pour un objet particulier. Vous pouvez même modifier les prototypes d'objets afin que toutes les nouvelles instances soient également enregistrées. J'ai utilisé Object.getOwnPropertyNames au lieu de for ... in, donc 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);
Peter Tseng
la source
-1

Voici du Javascript qui remplace ajoute console.log à chaque fonction en Javascript; Jouez avec sur Regex101 :

$re = "/function (.+)\\(.*\\)\\s*\\{/m"; 
$str = "function example(){}"; 
$subst = "$& console.log(\"$1()\");"; 
$result = preg_replace($re, $subst, $str);

C'est un «hack rapide et sale» mais je le trouve utile pour le débogage. Si vous avez beaucoup de fonctions, méfiez-vous car cela ajoutera beaucoup de code. En outre, le RegEx est simple et peut ne pas fonctionner pour des noms / déclarations de fonctions plus complexes.

hexicule
la source
-10

Vous pouvez en fait attacher votre propre fonction à console.log pour tout ce qui se charge.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Henrik Albrechtsson
la source
2
correct ou non, il ne répond pas à la question. du tout. (au cas où quelqu'un était ENCORE confus)
redfox05