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?
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?
Odpowiedzi:
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 augment
będą miały dodatkowego zachowania.
fn.apply(this, arguments);
nareturn fn.apply(this, arguments);
return
do najbardziej wewnętrznej funkcji.
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);
};
}());
Jest nowy sposób wykorzystania Proxy do osiągnięcia tej funkcjonalności w JS. załóżmy, że chcemy mieć a, console.log
ilekroć 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 Proxy
daje o wiele więcej funkcji niż samo rejestrowanie nazw konsoli.
Również ta metoda działa w node.js też.
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);
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.
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);
}