Adicionar console.log a todas as funções automaticamente

97

Existe uma maneira de fazer com que qualquer função produza uma instrução console.log quando for chamada registrando um gancho global em algum lugar (isto é, sem modificar a função real em si) ou por algum outro meio?

JRL
fonte
excelente pergunta, eu adoraria saber se isso é possível, mas tenho certeza que não é ... Talvez adicionar uma solicitação de recurso para que seja adicionado no mecanismo js do seu navegador favorito? :-)
Endophage
Pergunta perfeita, preciso de algo parecido com isto
mjimcua

Respostas:

62

Esta é uma maneira de aumentar todas as funções no namespace global com a função de sua escolha:

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

Uma desvantagem é que nenhuma função criada após a chamada augmentterá o comportamento adicional.

Wayne
fonte
Ele trata os valores de retorno da função corretamente?
SunnyShah
2
@SunnyShah Não, não funciona: jsfiddle.net/Shawn/WnJQ5 Mas este sim: jsfiddle.net/Shawn/WnJQ5/1 embora eu não tenha certeza de que funcionará em TODOS os casos ... A diferença está mudando fn.apply(this, arguments);parareturn fn.apply(this, arguments);
Shawn
2
@Shawn @SunnyShah corrigido. Só precisava adicionar um returnà função mais interna.
Wayne
funciona quase bem, mas recebo um erro com este jquery: call: if (jQuery.isFunction (lSrc)) e diz: TypeError: jQuery.isFunction não é uma função
fekiri malek
4
Esta solução não usa jQuery
Wayne
8

Para mim, esta parece ser a solução mais 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
fonte
7

Método proxy para registrar chamadas de função

Há uma nova maneira de usar o Proxy para obter essa funcionalidade em JS. suponha que queremos ter um console.logsempre que uma função de uma classe específica for chamada:

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

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

podemos substituir nossa instanciação de classe por um Proxy que substitui cada propriedade desta classe. tão:

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"

verifique se isso realmente funciona no Codepen


Lembre-se de que usar Proxyoferece muito mais funcionalidade do que apenas registrar nomes de console.

Além disso, este método funciona em Node.js também.

Soorena
fonte
Você também pode fazer isso sem usar instâncias e classes? Falando especificamente em node.js?
Revadike
@Revadike, isso deve ajudar: stackoverflow.com/a/28708700/5284370
Soorena
1

Se você quiser um registro mais direcionado, o código a seguir registrará as chamadas de função para um objeto específico. Você pode até mesmo modificar protótipos de objeto para que todas as novas instâncias também obtenham registro. Usei Object.getOwnPropertyNames em vez de for ... in, então ele funciona com classes ECMAScript 6, que não têm métodos enumeráveis.

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

Aqui estão alguns Javascript que substituem adiciona console.log a todas as funções em Javascript; Brinque com ele no Regex101 :

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

É um 'hack rápido e sujo', mas acho útil para depuração. Se você tiver muitas funções, tome cuidado, pois isso adicionará muito código. Além disso, o RegEx é simples e pode não funcionar para nomes / declarações de funções mais complexas.

hexículo
fonte
-10

Na verdade, você pode anexar sua própria função ao console.log para tudo o que carrega.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Henrik Albrechtsson
fonte
2
correto ou não, não responde à pergunta. em absoluto. (caso alguém AINDA estivesse confuso)
redfox05