我開始在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