Existe-t-il un moyen de faire en sorte qu'une fonction génère une instruction console.log lorsqu'elle est appelée en enregistrant un hook global quelque part (c'est-à-dire sans modifier la fonction réelle elle-même) ou via un autre moyen?
Voici un moyen d'augmenter toutes les fonctions de l'espace de noms global avec la fonction de votre choix:
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);
});
Un inconvénient est qu'aucune fonction créée après avoir appelé augment
n'aura le comportement supplémentaire.
Il existe une nouvelle façon d'utiliser Proxy pour obtenir cette fonctionnalité dans JS. supposons que nous voulons avoir un console.log
chaque fois qu'une fonction d'une classe spécifique est appelée:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const foo = new TestClass()
foo.a() // nothing get logged
nous pouvons remplacer notre instanciation de classe par un proxy qui remplace chaque propriété de cette classe. alors:
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"
vérifiez que cela fonctionne réellement dans Codepen
N'oubliez pas que l'utilisation de Proxy
vous offre beaucoup plus de fonctionnalités que la simple journalisation des noms de console.
Cette méthode fonctionne également dans Node.js également.
Si vous souhaitez une journalisation plus ciblée, le code suivant enregistrera les appels de fonction pour un objet particulier. Vous pouvez même modifier les prototypes d'objets afin que toutes les nouvelles instances soient également enregistrées. J'ai utilisé Object.getOwnPropertyNames au lieu de for ... in, donc cela fonctionne avec les classes ECMAScript 6, qui n'ont pas de méthodes énumérables.
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);
Voici du Javascript qui remplace ajoute console.log à chaque fonction en Javascript; Jouez avec sur Regex101 :
$re = "/function (.+)\\(.*\\)\\s*\\{/m";
$str = "function example(){}";
$subst = "$& console.log(\"$1()\");";
$result = preg_replace($re, $subst, $str);
C'est un "hack rapide et sale" mais je le trouve utile pour le débogage. Si vous avez beaucoup de fonctions, méfiez-vous car cela ajoutera beaucoup de code. De plus, le RegEx est simple et peut ne pas fonctionner pour des noms/déclarations de fonctions plus complexes.
Pour moi, cela ressemble à la solution la plus élégante:
(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);
};
}());