而不必为TRACE创建自定义记录器,例如在调用了哪些方法以及实例化了哪些类之后,是否有一种简单的方法可以使类下的所有方法都自行生成?这适用于node.js应用程序。
class MyClass
constructor: () ->
console.log 'MyClass:constructor'
doThat: () ->
console.log 'MyClass:doThat'
exports.MyClass = MyClass
myClass = new MyClass()
myClass.doThat()
如果我按照自己的方式行事,你会看到 4 日志消息而不是2(因此必须编写更少的代码来跟踪发生的事情)。
答案 0 :(得分:3)
我最近需要实现这样的东西来跟踪一些复杂的OO递归的东西。基本上,我想让一种方法“可追溯”而不会过多地污染它;所以也许解决方案也可以在这里应用。
首先,添加一个使其他功能可追溯的功能:
Function::trace = do ->
makeTracing = (ctorName, fnName, fn) ->
(args...) ->
console.log "#{ctorName}:#{fnName}"
fn.apply @, args
(arg) ->
for own name, fn of arg
@prototype[name] = makeTracing @name, name, fn
然后,要使用它,只需在要跟踪的每个方法之前添加@trace
:
class MyClass
@trace methodA: ->
@methodB 42
@trace methodB: ->
console.log "method b called with #{n}"
或者只添加一次@trace,然后再将所有可追踪方法缩进一个级别:
class MyClass
@trace
methodA: ->
@methodB 42
methodB: (n) ->
console.log "method b called with #{n}"
正如您所看到的,trace
有点滥用CoffeeScript的语法。 method: -> 'foo'
内的class MyClass
被解释为方法定义。但@trace method: -> 'foo'
被解释为调用trace
的{{1}}函数(这是MyClass
实例,我们已添加Function
函数)传递它带有一个trace
键的文字对象。在JavaScript中,它类似于method
。
this.trace({method: function() {return 'foo';}})
函数将只接受该对象并迭代它的键(方法名称)和值(方法),并将函数添加到记录其调用的trace
原型中,然后调用原始方法。
无论如何,MyClass
的输出将是:
(new MyClass).methodA()
此解决方案不适用于构造函数,因为它们不仅仅是常规方法。
你可以对此非常喜欢。您还可以记录传递给每个方法的参数,返回值,如果您愿意,甚至可以为嵌套调用添加缩进(如果您需要调试复杂的问题= D,则生成的跟踪非常有用)。
更新:作为一个更有趣的例子,这里是典型复合图案示例的迷你版本,几何图形和图形组:http://jsfiddle.net/2YuE7/具有更有趣的跟踪功能。所有数字都理解MyClass:methodA
MyClass:methodB
method b called with 42
方法。如果我们有这个复合数字,并在其上调用move
:
move
跟踪输出为:
f = new Composite [
new Rectangle 5, 10, 3, 4
new Composite [
new Circle 0, 0, 2
new Circle 0, 0, 4
new Circle 0, 0, 6
]
]
f.move 2, 3
答案 1 :(得分:0)
如果你想用普通的旧javascript做这件事,我创建了一个服务,你可以传递一个对象,该对象将返回一个具有记录每个方法的相同API的对象。请参阅http://jsfiddle.net/mcgraphix/pagkoLjb
处应用了polyfill的完整示例基本理念是:
var api = {
notAMethod: "blah",
foo: function() {
console.log("in foo", arguments);
},
bar: function(arg) {
this.foo(arg);
return this.notAMethod;
}
};
//wrap the api with a logging version
//to watch property changes and keep them in sync, you need the polyfill for Object.watch
// from https://gist.github.com/eligrey/384583
var createLogger = function(api) {
var loggingApi = {};
for (var prop in api) {
if (typeof api[prop] !== 'function') {
loggingApi[prop] = api[prop];
loggingApi.watch(prop, function(prop, oldVal, newVal){
api[prop] = newVal
return newVal;
});
} else {
loggingApi[prop] = function() {
console.log(prop + "() called with args: ", arguments);
var returnVal = api[prop].apply(api, arguments);
console.log(prop + "() returned: " + returnVal);
return returnVal;
}
}
}
return loggingApi;
};
api.foo('Shhhh... don\'t log me') //no logging
createLogger(api).foo(); //with logging