Automatyczne dodawanie console.log do każdej funkcji

97

Czy istnieje sposób, aby jakakolwiek funkcja wyświetlała instrukcję console.log, gdy jest wywoływana, rejestrując gdzieś globalny punkt zaczepienia (to znaczy bez modyfikowania samej funkcji) lub w inny sposób?

JRL
źródło
doskonałe pytanie, chciałbym wiedzieć, czy jest to możliwe, ale jestem prawie pewien, że tak nie jest ... Może dodać prośbę o dodanie funkcji do silnika js dla Twojej ulubionej przeglądarki? :-)
Endophage
Idealne pytanie, potrzebuję czegoś podobnego
mjimcua

Odpowiedzi:

62

Oto sposób na rozszerzenie wszystkich funkcji w globalnej przestrzeni nazw o wybraną funkcję:

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

Jedną z wad jest to, że żadne funkcje utworzone po wywołaniu nie augmentbędą miały dodatkowego zachowania.

Wayne
źródło
Czy poprawnie obsługuje zwracane wartości funkcji?
SunnyShah
2
@SunnyShah Nie, nie działa: jsfiddle.net/Shawn/WnJQ5 Ale ten tak: jsfiddle.net/Shawn/WnJQ5/1 chociaż nie jestem pewien, czy zadziała we WSZYSTKICH przypadkach ... Różnica zmienia się fn.apply(this, arguments);nareturn fn.apply(this, arguments);
Shawn,
2
@Shawn @SunnyShah Fixed. Wystarczyło dodać a returndo najbardziej wewnętrznej funkcji.
Wayne,
działa prawie dobrze, ale pojawia się błąd z tym jquery: call: if (jQuery.isFunction (lSrc)) i mówi: TypeError: jQuery.isFunction is not a function
fekiri malek
4
To rozwiązanie nie wykorzystuje jQuery
Wayne
8

Jak dla mnie wygląda to na najbardziej eleganckie rozwiązanie:

(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
źródło
7

Metoda proxy do rejestrowania wywołań funkcji

Jest nowy sposób wykorzystania Proxy do osiągnięcia tej funkcjonalności w JS. załóżmy, że chcemy mieć a, console.logilekroć wywoływana jest funkcja określonej klasy:

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

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

możemy zastąpić naszą instancję klasy serwerem proxy, który przesłania każdą właściwość tej klasy. więc:

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"

sprawdź, czy to faktycznie działa w Codepen


Pamiętaj, że używanie Proxydaje o wiele więcej funkcji niż samo rejestrowanie nazw konsoli.

Również ta metoda działa w node.js też.

Soorena
źródło
Czy możesz to również zrobić bez używania instancji i klas? Mówiąc konkretnie w node.js?
Revadike
@Revadike to powinno pomóc: stackoverflow.com/a/28708700/5284370
Soorena
1

Jeśli chcesz bardziej ukierunkowane rejestrowanie, poniższy kod będzie rejestrował wywołania funkcji dla określonego obiektu. Możesz nawet modyfikować prototypy Object, aby wszystkie nowe instancje również były rejestrowane. Użyłem Object.getOwnPropertyNames zamiast for ... in, więc działa z klasami ECMAScript 6, które nie mają wyliczalnych metod.

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
źródło
-1

Oto trochę JavaScript, który zastępuje dodanie console.log do każdej funkcji w Javascript; Graj z nim na Regex101 :

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

To „szybki i brudny hack”, ale uważam go za przydatny do debugowania. Jeśli masz dużo funkcji, uważaj, ponieważ doda to dużo kodu. Ponadto wyrażenie regularne jest proste i może nie działać w przypadku bardziej złożonych nazw / deklaracji funkcji.

heksykul
źródło
-10

W rzeczywistości możesz dołączyć własną funkcję do console.log dla wszystkiego, co się ładuje.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Henrik Albrechtsson
źródło
2
poprawne czy nie, nie odpowiada na pytanie. w ogóle. (gdyby ktoś NADAL był zdezorientowany)
redfox05