如何知道函数范围的javascript事件源?

时间:2013-05-24 14:50:56

标签: javascript events javascript-events

问题

是否可以知道函数是由用户事件还是异步事件(如回调)触发而没有原始事件参数?

背景

我正在尝试在更深层的函数调用中确定事件源,该调用不知道谁是原始事件触发器。

我必须知道为了调用弹出或重定向登录系统。但是这个函数是从很多地方调用的,所以我不能在所有调用者中传递event参数。

重要我无法将参数传递给最终功能。 <{1}}是不允许的。

e.g:

b('timer')

在该示例中,我尝试获取 <a onclick="b()" >call</a> <script> function a(){ b(); } function b(){ final(); } function final(){ //Is there something like this caller.event.source ? console.log(this.caller.event.source) } setTimeout(a,1000); source == 'timer'或任何其他信息以确定哪个是事件来源。

更新

基于basilikun方法,我实现了这个解决方案:

'onclick'

这是finddle

还有其他办法吗?

3 个答案:

答案 0 :(得分:3)

可以在最里面的函数中抛出异常,捕获它,并使用异常来确定调用堆栈。

如何获取调用堆栈的细节是特定于供应商的(FF中为e.stack,Opera中为e.message,IE和Safari中的粗略函数体解析),但{ {3}}。

至少,这是我可以从该页面上发布的简短片段中得出的结论。请注意,这已经演变为eriwen.com,因此可能比该页面上的50行代码段更可靠,功能更强大。

在您的示例中,您将使用:

function b(){
    final();
}
function final(){
   var trace = printStackTrace();
   //output trace
}


//This would be attached as the click handler for the anchor
function anchorHandler(){
   b();
}
setTimeout(function timerCallback(){
    b();
}, 1000);

根据跟踪中是否有timerCallbackanchorHandler,您知道哪个事件触发了函数调用。

答案 1 :(得分:2)

假设你至少可以在第一个函数a中传递“timer”:

Fiddle

<a onclick="a()" >call</a>

<script>

function a(){
    b();
}

function b(){
    final();
}

function final(){
    var callerFunction = arguments.callee.caller;
    var evtArg = callerFunction.arguments[0];
    while (callerFunction.caller !== null) {
        callerFunction = callerFunction.caller;
        if (callerFunction.arguments[0]) {
            evtArg = callerFunction.arguments[0];
        }
    }
    console.log(evtArg);
}

setTimeout(function(){a("timer")}, 100);

</script>

这将为您提供函数调用链中最后一个可能的第一个参数。因此,如果您使用“普通”事件,它将为您提供事件对象。如果您使用超时,它将为您提供传递给第一个函数的任何内容。

请注意,此解决方案还使用arguments.callee.caller,它应该很慢并且不支持任何地方。正如robC已经提到的那样,严格模式下不允许这样做。

答案 2 :(得分:1)

您可以使用arguments.callee.caller来访问函数对象并附加一个expando ...不确定这是否适用于您的情况。请注意,这不会在严格模式下工作,因为不推荐使用arguments.callee.caller。

<a onclick="b()" >call</a>

<script>

   function a(){
      b.calledByA = true;
      b();
   }

   function b(){
      final();
   }

   function final(){
      var caller = arguments.callee.caller;
      console.log(caller.calledByA);
      caller.calledByA = null;
   }

   setTimeout(a, 1000);

</script>