【问题标题】:How to find out where a function is called from in JavaScript?如何找出在 JavaScript 中调用函数的位置?
【发布时间】:2013-06-27 20:52:11
【问题描述】:

是否有可能找出调用函数的位置?如果是,那么 如何检测一个函数是从全局范围另一个函数还是浏览器控制台调用的?

看看下面的例子:

<script>
    function myFunc1() {
        // some code
        myFunc2(); // I was called from myFunc1()
    }
    function myFunc2() {
        var callerName = new String;
        callerName = arguments.callee.caller.name;
        // some code
        alert('I was called from ' + callerName + ' function');
    }
    myFunc2(); // I was called from global scope
</script>

我知道上面示例中的这一行 callerName = arguments.callee.caller.name; 会给我调用函数的名称。 但我不知道如何检测函数是否从全局调用 例如,如果我更改myFunc2() 并添加if else 语句来检查arguments.callee.caller.name 是否返回undefined 值,知道这会发生,当从全局范围调用函数时:

myFunc2() {
var callerName = new String;
callerName = arguments.callee.caller.name;
    if(callerName == undefined) {
        alert('I was called from global scope');
    } else {
        alert('I was called from ' + callerName + ' function');
    }
}

但是,如果从全局范围调用 myFunc2(),这将不起作用,并且 callerName = arguments.callee.caller.name; 将导致 JavaScript 抛出以下错误:

TypeError: 'null' is not an object (evaluating 'arguments.callee.caller.name')

所以我回到第一方,问题仍然存在:

  • 如何检测是否从全局范围调用函数?
  • 如果它是从全局范围调用的,是从浏览器控制台调用的吗?

【问题讨论】:

  • x = arguments.callee.caller ? arguments.callee.caller.name : "global"; 我想会修复你的 TypeError 。 null.name 没有意义,会产生错误。
  • 这行得通,但你能解释一下如何吗?此语句中发生了什么:x = arguments.callee.caller ? arguments.callee.caller.name
  • ? 是二元运算符。 x = arguments.callee.caller ? arguments.callee.caller.name : "global"; 将评估 (boolean) arguments.callee.caller。如果这是真的,那么它会将arguments.callee.caller.name 分配给x。如果它是假的,那么它会将"global" 分配给x。 (boolean) nullfalse,防止代码尝试获取它的名称。
  • 所以callerName = arguments.callee.caller ? arguments.callee.caller.name : "global"; 等于:if(arguments.callee.caller) { callerName = arguments.callee.caller.name; } else { callerName = "global"; }
  • 是的,但是在这种情况下二元运算符更容易阅读。

标签: javascript function call


【解决方案1】:

如果从全局范围调用函数,arguments.callee.caller.name 将未定义。否则,它将是调用函数的名称(也表示调用它的范围)。

所以你已经拥有的应该可以工作,除了strict modearguments.callee 不可用。


另外:浏览器中可用的开发人员工具可能是检查此类事情的更好方法:只需设置一个断点并查看堆栈跟踪面板。当然,除非您的代码本身需要在运行时知道调用范围。

【讨论】:

    【解决方案2】:

    根据您的浏览器,您可能会通过访问未定义的变量(例如,在 try/catch 中)来引发错误。然后检查一些浏览器在错误中提供的堆栈跟踪。

    这将是特定于浏览器的。

    【讨论】:

    • 附带说明,eriwen.com/javascript/js-stack-trace 的工作原理基本上是这样
    • 喜欢这个想法,但“挑衅”错误似乎令人困惑。为什么不扔一个?
    • 您不必使用try/catch。只需new Error().stack 就会显示相同的信息。
    【解决方案3】:

    在 JavaScript 中,大多数东西都是对象,当您声明 callerName = new String 时,您会创建一个带有一些属性和方法的 字符串对象。例如,valueOf() 方法将返回 字符串对象的原始值。 但是,就像 JavaScript 告诉您 'TypeError: 'null' is not an object null 不是对象 一样, 这是缺少对象。 null 没有任何方法或属性。 当从全局范围调用函数时,arguments.callee.caller 将调用者评估为 null。 所以arguments.callee.caller.name 就像试图访问null 的name 属性(null.name,但是null 没有名为name 的属性, 因为它不是一个对象,并且 不能 有任何属性。这就是 JavaScript 抱怨的原因,因为您试图访问不存在的东西。但是,您可以做的是首先检查 caller是一个假值,通过使用简单的if else 语句if(!arguments.callee.caller)如果不是,那么您可以访问callername 属性并找出什么函数调用了myFunc2()但如果是,那么你知道该函数是从全局范围调用的。

    function myFunc2() {
        if(!arguments.callee.caller) {
            callerName = "global";
            alert('I was called from global scope');
        } else {
            callerName = arguments.callee.caller.name;
            alert('I was called from ' + callerName + ' function');
        }
    }
    

    【讨论】:

    • 请考虑将callerName设置为函数本地,否则会污染窗口。
    【解决方案4】:

    这是一个相当棘手的问题。正如在这个答案中所讨论的,Arguments.callee 在某些浏览器中已被弃用。

    根据您的方法,您可以使用 Function.caller。 我写了一个相当simple example

    function A() {
        if (A.caller === null || A.caller.name == "") console.log("Function called from top window")
        else console.log("Called from " + A.caller.name);
        B();
    }
    
    function B() {
        if (B.caller === null || B.caller.name == "") console.log("Function called from top window")
        else console.log("Called from " + B.caller.name);
    }
    
    A();
    

    另一个更通用的例子可以找到here

    仍然'use strict' 使这两种方法都失败,因此使用try / catch 块可以解决您的问题,或者您可以为您的函数模拟“dummy call stack”(取决于所有代码同步工作的事实)

    【讨论】:

      【解决方案5】:

      function func1() {
          // some code
          func2(); // I was called from func1()
      }
      function func2() {
      var callerName = new String;
      callerName = arguments.callee.caller ? arguments.callee.caller.name : "global";
          if(callerName == "global") {
              alert('I was called from global scope');
          } else {
              alert('I was called from ' + callerName + ' function');
          }
      }
      func1();
      func2(); // I was called from global scope

      func2 被调用它将显示它的调用者名称,如果它是在另一个函数范围内调用的,它将显示该函数的名称,如果它是从全局范围调用的,它将显示一条消息,表明它是从全局范围调用的.

      【讨论】:

        【解决方案6】:

        在 Chrome 中,您可以使用:

        console.trace();
        

        只要在你的函数中添加那一行,我通常把它放在第一行。如果您查看控制台,您会看到函数的名称,并且在该行下方,您会看到调用它的位置。

        【讨论】:

        • 这应该是公认的答案,简单且非常有用!
        猜你喜欢
        • 2018-03-20
        • 2023-03-10
        • 2018-08-10
        • 1970-01-01
        • 2012-01-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多