自动为每个函数添加 console. log

有没有一种方法可以通过在某处注册一个全局钩子(即不修改实际函数本身)或通过其他方法使任何函数在调用时输出一个 console.log 语句?

50245 次浏览

这里有一种方法可以用您选择的函数来增加全局名称空间中的所有函数:

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

一个缺点是,在调用 augment之后创建的函数都不会有额外的行为。

实际上,您可以将自己的函数附加到 console.log 中,以便加载所有内容。

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

Here's some Javascript which replaces adds console.log to every function in Javascript; Play with it on Regex101:

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

这是一个“快速而肮脏的黑客行为”,但我发现它对调试非常有用。如果你有很多函数,要小心,因为这会增加很多代码。另外,RegEx 很简单,可能不适用于更复杂的函数名/声明。

如果需要更有针对性的日志记录,下面的代码将记录特定对象的函数调用。您甚至可以修改 Object 原型,以便所有新的实例都能够进行日志记录。我使用 Object.getOwnPropertyNames 而不是 for... in,所以它适用于 ECMAScript 6类,这些类没有可枚举方法。

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

记录函数调用的代理方法

在 JS 中使用 < strong > Proxy 实现这一功能有一种新的方法。 assume that we want to have a console.log whenever a function of a specific class is called:

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


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

我们可以用一个代理来替换我们的类实例化,代理覆盖了这个类的每个属性:

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"

check that this actually works in Codepen


请记住,使用 Proxy可以提供比仅记录控制台名称更多的功能。

这种方法也适用于 Node.js

在我看来,这似乎是最优雅的解决方案:

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