我开始在JS的动态分析工具上工作,并且希望不显眼地分析整个环境。我基本上遍历各种上下文,深入挖掘对象,并且每次我点击一个函数时,都会将它钩住。现在,这个工作相对较好,除了它与像图书馆打交道时打破了事实上的jQuery /原型等当递归挂钩时,Javascript丢失上下文
这是我的代码迄今(评论尽我的能力):
var __PROFILER_global_props = new Array(); // visited properties
/**
* Hook into a function
* @name the name of the function
* @fn the reference to the function
* @parent the parent object
*/
function __PROFILER_hook(name, fn, parent) {
//console.log('hooking ' + name + ' ' + fn + ' ' + parent);
if (typeof parent == 'undefined')
parent = window;
for (var i in parent) {
// find the right function
if (parent[i] === fn) {
// hook into it
console.log('--> hooking ' + name);
parent[i] = function() {
console.log('called ' + name);
return fn.apply(parent, arguments);
}
//parent[i] = fn; // <-- this works (obviously)
break;
}
}
}
/**
* Traverse object recursively, looking for functions or objects
* @obj the object we're going into
* @parent the parent (used for keeping a breadcrumb)
*/
function __PROFILER_traverse(obj, parent) {
for (i in obj) {
// get the toString object type
var oo = Object.prototype.toString.call(obj[i]);
// if we're NOT an object Object or an object Function
if (oo != '[object Object]' && oo != '[object Function]') {
console.log("...skipping " + i);
// skip
// ... the reason we do this is because Functions can have sub-functions and sub-objects (just like Objects)
continue;
}
if (__PROFILER_global_props.indexOf(i) == -1 // first we want to make sure we haven't already visited this property
&& (i != '__PROFILER_global_props' // we want to make sure we're not descending infinitely
&& i != '__PROFILER_traverse' // or recusrively hooking into our own hooking functions
&& i != '__PROFILER_hook' // ...
&& i != 'Event' // Event tends to be called a lot, so just skip it
&& i != 'log' // using FireBug for debugging, so again, avoid hooking into the logging functions
&& i != 'notifyFirebug')) { // another firebug quirk, skip this as well
// log the element we're looking at
console.log(parent+'.'+i);
// push it.. it's going to end up looking like '__PROFILER_BASE_.something.somethingElse.foo'
__PROFILER_global_props.push(parent+'.'+i);
try {
// traverse the property recursively
__PROFILER_traverse(obj[i], parent+'.'+i);
// hook into it (this function does nothing if obj[i] is not a function)
__PROFILER_hook(i, obj[i], obj);
} catch (err) {
// most likely a security exception. we don't care about this.
}
} else {
// some debugging
console.log(i + ' already visited');
}
}
}
这是配置文件,这是我如何调用它:
// traverse the window
__PROFILER_traverse(window, '__PROFILER_BASE_');
// testing this on jQuery.com
$("p.neat").addClass("ohmy").show("slow");
遍历工作正常,挂钩工作正常,只要功能是简单的和非匿名的(我想钩住匿名函数是不可能的,所以我不太担心了)。
这是预处理阶段的一些修剪输出。
notifyFirebug already visited
...skipping firebug
...skipping userObjects
__PROFILER_BASE_.loadFirebugConsole
--> hooking loadFirebugConsole
...skipping location
__PROFILER_BASE_.$
__PROFILER_BASE_.$.fn
__PROFILER_BASE_.$.fn.init
--> hooking init
...skipping selector
...skipping jquery
...skipping length
__PROFILER_BASE_.$.fn.size
--> hooking size
__PROFILER_BASE_.$.fn.toArray
--> hooking toArray
__PROFILER_BASE_.$.fn.get
--> hooking get
__PROFILER_BASE_.$.fn.pushStack
--> hooking pushStack
__PROFILER_BASE_.$.fn.each
--> hooking each
__PROFILER_BASE_.$.fn.ready
--> hooking ready
__PROFILER_BASE_.$.fn.eq
--> hooking eq
__PROFILER_BASE_.$.fn.first
--> hooking first
__PROFILER_BASE_.$.fn.last
--> hooking last
__PROFILER_BASE_.$.fn.slice
--> hooking slice
__PROFILER_BASE_.$.fn.map
--> hooking map
__PROFILER_BASE_.$.fn.end
--> hooking end
__PROFILER_BASE_.$.fn.push
--> hooking push
__PROFILER_BASE_.$.fn.sort
--> hooking sort
__PROFILER_BASE_.$.fn.splice
--> hooking splice
__PROFILER_BASE_.$.fn.extend
--> hooking extend
__PROFILER_BASE_.$.fn.data
--> hooking data
__PROFILER_BASE_.$.fn.removeData
--> hooking removeData
__PROFILER_BASE_.$.fn.queue
当我jQuery.com(通过萤火虫)执行$("p.neat").addClass("ohmy").show("slow");
,我得到一个适当的调用堆栈,但我似乎失去了地方我的上下文一路上,因为什么也没有发生,我得到一个jQuery的错误e is undefined
(显然,挂钩拧了一些东西)。
called init
called init
called find
called find
called pushStack
called pushStack
called init
called init
called isArray
called isArray
called merge
called merge
called addClass
called addClass
called isFunction
called isFunction
called show
called show
called each
called each
called isFunction
called isFunction
called animate
called animate
called speed
called speed
called isFunction
called isFunction
called isEmptyObject
called isEmptyObject
called queue
called queue
called each
called each
called each
called each
called isFunction
called isFunction
的问题是,我想打电话
return fn.apply(parent, arguments);
这里还有一个有趣的怪癖,当我失去了this
上下文。如果我前面的勾我遍历,即:
// hook into it (this function does nothing if obj[i] is not a function)
__PROFILER_hook(i, obj[i], obj);
// traverse the property recursively
__PROFILER_traverse(obj[i], parent+'.'+i);
..应用程序运行完全正常,但调用堆栈被改变(我似乎并没有得到jQuery的特定功能)由于某种原因:
called $
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called setInterval
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called clearInterval
..而不是animation
,show
,merge
等眼下,所有的挂钩并是说called functionName
但最终我想要做的堆栈跟踪和时间功能(通过Java小程序)。
这个问题最终是巨大的,我很抱歉,但任何帮助表示赞赏!
注意:如果您不小心,上述代码可能会导致浏览器崩溃。公平的警告:P
相似的问题:http://stackoverflow.com/questions/5033836/adding-console-log-to-every-function-automatically – 2011-05-31 20:02:39