Javascript在递归挂接时丢失上下文

Javascript在递归挂接时丢失上下文,javascript,recursion,hook,language-features,Javascript,Recursion,Hook,Language Features,我正在开始为JS开发一个动态分析工具,我想以不引人注目的方式分析整个环境。我基本上是在遍历各种上下文,深入挖掘对象,每次我点击一个函数,我就钩住它。现在,除了在处理jQuery/prototype等库时会中断之外,这种方法工作得相对较好 这是我迄今为止的代码(已尽我所能进行了评论): 只要函数简单且非匿名,遍历和钩住就可以很好地工作(我认为钩住匿名函数是不可能的,所以我不太担心) 这是预处理阶段的一些修剪输出 notifyFirebug already visited ...skipping f

我正在开始为JS开发一个动态分析工具,我想以不引人注目的方式分析整个环境。我基本上是在遍历各种上下文,深入挖掘对象,每次我点击一个函数,我就钩住它。现在,除了在处理jQuery/prototype等库时会中断之外,这种方法工作得相对较好

这是我迄今为止的代码(已尽我所能进行了评论):

只要函数简单且非匿名,遍历和钩住就可以很好地工作(我认为钩住匿名函数是不可能的,所以我不太担心)

这是预处理阶段的一些修剪输出

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
当我执行
$(“p.neat”).addClass(“ohmy”).show(“slow”)e is undefined
错误(很明显,连接搞砸了)

问题是,我认为我在调用时丢失了
这个
上下文

return fn.apply(parent, arguments);
还有一个有趣的怪癖。如果我在横穿前钩住,即:

        // 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
。。而不是
动画
显示
合并
,等等。现在,钩子所做的只是说
调用functionName
,但最终我想做堆栈跟踪和时间函数(通过Java小程序)

这个问题很严重,我向您道歉,但我们非常感谢您的帮助


注意:如果不小心,上述代码可能会使浏览器崩溃。公正的警告:我认为你的思路是对的。当您使用
apply
时,
this
的值将被删除。jQuery中定义的函数可能是通过
apply
内部调用的,并且取决于
this
的值

apply
的第一个参数是将用于
的值。您确定应该为此使用
parent

我可以通过以下方式复制该问题:

var obj = {
   fn : function() { 
      if(this == "monkeys") {
         console.log("Monkeys are funny!");
      }

      else {
         console.log("There are no monkeys :(");
      }
   }
};

obj.fn.apply("monkeys");

var ref = obj.fn;

//assuming parent here is obj
obj.fn = function() {
   console.log("hooking to obj.fn");
   return ref.apply(obj);
};

obj.fn.apply("monkeys");
这里,函数取决于
this
的值来打印文本
猴子很有趣。如您所见,使用
hook
算法,此上下文将丢失。Firebug显示:

Monkeys are funny! hooking to obj.fn There are no monkeys :( 这次Firebug说:

Monkeys are funny! hooking to obj.fn Monkeys are funny! 因此,如果在应用程序中使用
this
而不是
parent
,您的问题可能会得到解决

如果我没有正确理解你的问题,我向你道歉。无论我哪里错了,请纠正我

更新

jQuery中有两种函数。附加到
jQuery
对象本身的方法(类似于静态方法),然后您就有了对
jQuery(选择器)
的结果进行操作的方法(类似于实例方法)。你需要关心的是后者。在这里,
这个
非常重要,因为这就是实现链接的方式

我能够让下面的例子起作用。请注意,我正在处理对象的实例,而不是对象本身。因此,在您的示例中,我将处理
jQuery(“someId”)
,而不仅仅是
jQuery

var obj = function(element) {
   this.element = element;
   this.fn0 = function(arg) {
      console.log(arg, element);
      return this;
   }

   this.fn1 = function(arg) {
      console.log(arg, arg, element);
      return this;
   }

   if(this instanceof obj) {
      return this.obj;
   }

   else {
      return new obj(element);
   }
};

var objInst = obj("monkeys");

var ref0 = objInst.fn0;

objInst.fn0 = function(arg) {
   console.log("calling f0");
   return ref0.apply(this, [arg]);
};

var ref1 = objInst.fn1;

objInst.fn1 = function(arg) {
   console.log("calling f1");
   return ref1.apply(this, [arg]);
};

objInst.fn0("hello").fn1("bye");

我不知道这是否解决了你的问题。也许查看jQuery源代码会给您提供更多的见解:)。我认为您的困难在于区分通过
apply
调用的函数和通过链接(或直接调用)调用的函数。

您完全理解这一点,我以前也尝试过
this
,但如果我使用
this
,似乎函数链接会中断(比如说,
$('something').addClass('asdfg').show('slow')
停止工作)
未定义。@David我更新了我的答案。我不知道它是否回答了您的问题,但我尝试了:p我在答案中提到了这一点,但我认为,当您试图区分通过
apply
调用的函数与通过链接或直接调用的函数时,您将面临困难。我对kn感兴趣由于这个问题的解决方案也是如此,所以希望其他比我更有知识的人能够插话进来。尽管在一般情况下这可能无法解决问题,但我的直觉告诉我,这应该是可能的,我欣赏你的见解。我想你在区分方法链接和统计时一针见血调用ic方法。另外,在做一些试验时,我发现有时调用自己的数组中的apply-wraps参数。这很奇怪。类似的问题: Monkeys are funny! hooking to obj.fn There are no monkeys :(
obj.fn = function() {
   console.log("hooking to obj.fn");
   return ref.apply(this);
};
Monkeys are funny! hooking to obj.fn Monkeys are funny!
return fn.apply(this, arguments);
var obj = function(element) {
   this.element = element;
   this.fn0 = function(arg) {
      console.log(arg, element);
      return this;
   }

   this.fn1 = function(arg) {
      console.log(arg, arg, element);
      return this;
   }

   if(this instanceof obj) {
      return this.obj;
   }

   else {
      return new obj(element);
   }
};

var objInst = obj("monkeys");

var ref0 = objInst.fn0;

objInst.fn0 = function(arg) {
   console.log("calling f0");
   return ref0.apply(this, [arg]);
};

var ref1 = objInst.fn1;

objInst.fn1 = function(arg) {
   console.log("calling f1");
   return ref1.apply(this, [arg]);
};

objInst.fn0("hello").fn1("bye");