Agregar console.log a cada función automáticamente

97

¿Hay alguna manera de hacer que una función genere una declaración console.log cuando se llama registrando un gancho global en algún lugar (es decir, sin modificar la función real) o por algún otro medio?

JRL
fuente
excelente pregunta, me encantaría saber si esto es posible, pero estoy bastante seguro de que no lo es ... ¿Quizás agregar una solicitud de función para que se agregue en el motor js de su navegador favorito? :-)
Endophage
Pregunta perfecta, necesito algo similar a esto
mjimcua

Respuestas:

62

Esta es una forma de aumentar todas las funciones en el espacio de nombres global con la función que elija:

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

Una desventaja es que ninguna función creada después de la llamada augmenttendrá el comportamiento adicional.

Wayne
fuente
¿Maneja correctamente los valores de retorno de la función?
SunnyShah
2
@SunnyShah No, no lo hace: jsfiddle.net/Shawn/WnJQ5 Pero este sí lo hace: jsfiddle.net/Shawn/WnJQ5/1 aunque no estoy seguro de que funcione en TODOS los casos ... La diferencia está cambiando fn.apply(this, arguments);areturn fn.apply(this, arguments);
Shawn
2
@Shawn @SunnyShah Corregido. Solo necesitaba agregar returna la función más interna.
Wayne
funciona casi bien, pero aparece un error con este jquery: call: if (jQuery.isFunction (lSrc)) y dice: TypeError: jQuery.isFunction no es una función
fekiri malek
4
Esta solución no usa jQuery
Wayne
8

En cuanto a mí, esta parece la solución más elegante:

(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
fuente
7

Método proxy para registrar llamadas a funciones

Hay una nueva forma de usar Proxy para lograr esta funcionalidad en JS. Supongamos que queremos tener un console.logsiempre que se llame a una función de una clase específica:

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

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

podemos reemplazar la instanciación de nuestra clase con un Proxy que anule cada propiedad de esta clase. entonces:

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"

compruebe que esto realmente funciona en Codepen


Recuerde que el uso Proxyle brinda muchas más funciones que solo registrar nombres de consola.

Además, este método funciona en Node.js también.

Soorena
fuente
¿También puedes hacer esto sin usar instancias y clases? Específicamente hablando en node.js?
Revadike
@Revadike esto debería ayudar: stackoverflow.com/a/28708700/5284370
Soorena
1

Si desea un registro más específico, el siguiente código registrará las llamadas a funciones para un objeto en particular. Incluso puede modificar los prototipos de objetos para que todas las instancias nuevas también se registren. Usé Object.getOwnPropertyNames en lugar de para ... in, por lo que funciona con las clases ECMAScript 6, que no tienen métodos enumerables.

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
fuente
-1

Aquí hay algo de Javascript que reemplaza agrega console.log a cada función en Javascript; Juega con él en Regex101 :

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

Es un 'truco rápido y sucio' pero lo encuentro útil para depurar. Si tiene muchas funciones, tenga cuidado porque esto agregará mucho código. Además, la expresión regular es simple y es posible que no funcione para declaraciones o nombres de funciones más complejos.

hexiculo
fuente
-10

De hecho, puede adjuntar su propia función a console.log para todo lo que se carga.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Henrik Albrechtsson
fuente
2
correcto o no, no responde a la pregunta. en absoluto. (en caso de que alguien todavía estuviera confundido)
redfox05