C'è un modo per fare in modo che qualsiasi funzione emetta un'istruzione console.log quando viene chiamata registrando un hook globale da qualche parte (cioè senza modificare la funzione stessa) o tramite altri mezzi?
C'è un modo per fare in modo che qualsiasi funzione emetta un'istruzione console.log quando viene chiamata registrando un hook globale da qualche parte (cioè senza modificare la funzione stessa) o tramite altri mezzi?
Risposte:
Ecco un modo per aumentare tutte le funzioni nello spazio dei nomi globale con la funzione di tua scelta:
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);
});
Uno svantaggio è che nessuna funzione creata dopo la chiamata augment
avrà il comportamento aggiuntivo.
fn.apply(this, arguments);
inreturn fn.apply(this, arguments);
return
alla funzione più interna.
Quanto a me, questa sembra la soluzione più 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);
};
}());
C'è un nuovo modo di utilizzare Proxy per ottenere questa funzionalità in JS. supponiamo di voler avere un console.log
ogni volta che viene chiamata una funzione di una classe specifica:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const foo = new TestClass()
foo.a() // nothing get logged
possiamo sostituire la nostra istanza di classe con un proxy che sovrascrive ogni proprietà di questa classe. così:
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"
controlla che funzioni effettivamente in Codepen
Ricorda che l'utilizzo Proxy
ti offre molte più funzionalità rispetto alla semplice registrazione dei nomi delle console.
Anche questo metodo funziona in Node.js troppo.
Se si desidera una registrazione più mirata, il codice seguente registrerà le chiamate di funzione per un particolare oggetto. Puoi anche modificare i prototipi di oggetti in modo che anche tutte le nuove istanze vengano registrate. Ho usato Object.getOwnPropertyNames invece di per ... in, quindi funziona con le classi ECMAScript 6, che non hanno metodi enumerabili.
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);
Ecco alcuni Javascript che sostituiscono aggiunge console.log a ogni funzione in Javascript; Gioca con esso su Regex101 :
$re = "/function (.+)\\(.*\\)\\s*\\{/m";
$str = "function example(){}";
$subst = "$& console.log(\"$1()\");";
$result = preg_replace($re, $subst, $str);
È un "trucco rapido e sporco" ma lo trovo utile per il debug. Se hai molte funzioni, fai attenzione perché questo aggiungerà molto codice. Inoltre, la RegEx è semplice e potrebbe non funzionare per nomi / dichiarazioni di funzioni più complesse.
Puoi effettivamente collegare la tua funzione a console.log per tutto ciò che viene caricato.
console.log = function(msg) {
// Add whatever you want here
alert(msg);
}