Automatisches Hinzufügen von console.log zu jeder Funktion


97

Gibt es eine Möglichkeit, eine Funktion dazu zu bringen, eine console.log-Anweisung auszugeben, wenn sie aufgerufen wird, indem irgendwo ein globaler Hook registriert wird (dh ohne die eigentliche Funktion selbst zu ändern) oder auf andere Weise?


Ausgezeichnete Frage, ich würde gerne wissen, ob dies möglich ist, aber ich bin mir ziemlich sicher, dass dies nicht der Fall ist. Vielleicht fügen Sie eine Funktionsanforderung hinzu, damit sie in der js-Engine für Ihren Lieblingsbrowser hinzugefügt wird. :-)
Endophage

Perfekte Frage, ich brauche so etwas Ähnliches
mjimcua

Antworten:


62

Hier ist eine Möglichkeit, alle Funktionen im globalen Namespace mit der Funktion Ihrer Wahl zu erweitern:

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

Ein Nachteil ist, dass keine nach dem Aufruf erstellten Funktionen augmentdas zusätzliche Verhalten aufweisen.


Behandelt es Rückgabewerte der Funktion richtig?
SunnyShah

2
@SunnyShah Nein, das tut es nicht: jsfiddle.net/Shawn/WnJQ5 Aber das tut es: jsfiddle.net/Shawn/WnJQ5/1, obwohl ich nicht sicher bin, ob es in ALLEN Fällen funktionieren wird ... Der Unterschied ändert sich fn.apply(this, arguments);zureturn fn.apply(this, arguments);
Shawn

2
@Shawn @SunnyShah Behoben. Muss nur zur returninnersten Funktion hinzugefügt werden.
Wayne

funktioniert fast gut, aber ich bekomme einen Fehler mit dieser jquery: call: if (jQuery.isFunction (lSrc)) und es heißt: TypeError: jQuery.isFunction ist keine Funktion
fekiri malek

4
Diese Lösung verwendet nicht jQuery
Wayne

8

Für mich scheint dies die eleganteste Lösung zu sein:

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

7

Proxy-Methode zum Protokollieren von Funktionsaufrufen

Es gibt eine neue Möglichkeit, Proxy zu verwenden, um diese Funktionalität in JS zu erreichen. Nehmen wir an, wir möchten eine haben, console.logwenn eine Funktion einer bestimmten Klasse aufgerufen wird:

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

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

Wir können unsere Klasseninstanziierung durch einen Proxy ersetzen, der jede Eigenschaft dieser Klasse überschreibt. so:

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"

Überprüfen Sie, ob dies in Codepen tatsächlich funktioniert


Denken ProxySie daran, dass die Verwendung viel mehr Funktionen bietet, als nur Konsolennamen zu protokollieren.

Auch diese Methode funktioniert in Node.js auch.


Können Sie dies auch ohne Verwendung von Instanzen und Klassen tun? Speziell in node.js?
Revadike

@Revadike dies sollte helfen: stackoverflow.com/a/28708700/5284370
Soorena

1

Wenn Sie eine gezieltere Protokollierung wünschen, protokolliert der folgende Code Funktionsaufrufe für ein bestimmtes Objekt. Sie können sogar Objektprototypen so ändern, dass auch alle neuen Instanzen protokolliert werden. Ich habe Object.getOwnPropertyNames anstelle von for ... in verwendet, daher funktioniert es mit ECMAScript 6-Klassen, die keine aufzählbaren Methoden haben.

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

-1

Hier ist etwas Javascript, das das Hinzufügen von console.log zu jeder Funktion in Javascript ersetzt. Spielen Sie damit auf Regex101 :

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

Es ist ein "schneller und schmutziger Hack", aber ich finde ihn nützlich zum Debuggen. Wenn Sie viele Funktionen haben, achten Sie darauf, dass dadurch viel Code hinzugefügt wird. Außerdem ist RegEx einfach und funktioniert möglicherweise nicht für komplexere Funktionsnamen / Deklarationen.


-10

Sie können Ihre eigene Funktion für alles, was geladen wird, an console.log anhängen.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}

2
richtig oder nicht, es beantwortet die Frage nicht. überhaupt. (falls jemand noch verwirrt war)
redfox05
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.