如何知道函数作用域上的JavaScript事件源

How to know the JavaScript event source on function scope?

本文关键字:JavaScript 事件源 作用域 何知道 函数      更新时间:2023-09-26

问题

在没有原始事件参数的情况下,是否可以知道函数是由用户事件还是异步事件(如回调(触发的?

背景

我试图在一个更深层次的函数调用中确定事件源,该函数不知道谁是最初的事件触发器。

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

重要我无法将参数传递给最终函数。不允许使用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''onclick',或任何其他信息,以确定哪个是事件起源。

更新

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

function final(){
    var callerFunction = arguments.callee.caller,
    evtArg = callerFunction.arguments[0];
    while(callerFunction.caller){
        callerFunction = callerFunction.caller;
        if (callerFunction.arguments[0]) {
            evtArg = callerFunction.arguments[0];
        }
    }
    console.log(evtArg&&evtArg.type?'event fired by user':'event async');
}

这是finddle

还有其他方法吗?

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

如何获得调用堆栈的细节是特定于供应商的(FF中的e.stack,Opera中的e.message,IE和Safari中的粗略函数体解析(,但eriwen.com上存在一个相当稳健的实现。

至少,这是我可以从该页面上发布的简短片段中了解到的。请注意,这已经发展成为Github上的一个完整的项目,因此可能比该页面上的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);

根据跟踪中是timerCallback还是anchorHandler,您可以知道是什么事件触发了函数调用。

假设您至少可以在第一个函数a:中传递"计时器">

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已经提到的,在严格模式下是不允许的。

您可以使用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>