27

Is it possible to find out where a function is called from? If yes, then how to detect, if a function is called from a global scope, from another function, or perhaps from a browser console?

Take a look at the following example:

<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>

I know that this line callerName = arguments.callee.caller.name;in the example above, would give me caller function's name. But I don't know how to detect if a function was called from a global scope. For instance if I change myFunc2() and add an if else statement to check if arguments.callee.caller.name returns an undefined value, knowing that this will happen, when a function is called from a global scope:

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');
    }
}

However, this will not work if myFunc2() is called from a global scope and callerName = arguments.callee.caller.name; will cause JavaScript to throw the following error:

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

So I am back to square one, and the question still remains:

  • How to detect if a function is called from a global scope?
  • If it's called from a global scope, is it from a browser console?
4

6 回答 6

27

在 Chrome 中,您可以使用:

console.trace();

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

于 2017-04-07T16:08:26.793 回答
8

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

所以你已经拥有的应该可以工作,除了在严格模式arguments.callee不可用的地方。


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

于 2013-06-30T16:44:51.623 回答
4

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

这将是非常特定于浏览器的。

于 2013-06-30T16:58:34.003 回答
2

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 被调用它将显示它的调用者名称,如果它是在另一个函数范围内调用的,它将显示该函数的名称,如果它是从全局范围调用的,它将显示一条消息,表明它是从全局范围调用的。

于 2015-01-25T08:04:53.243 回答
1

在 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 elseif(!arguments.callee.caller)namecallermyFunc2()

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');
    }
}
于 2013-06-30T20:51:27.430 回答
1

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

根据您的方法,您可以使用 Function.caller。我写了一个非常简单的例子

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();

另一个更通用的例子可以在这里找到

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

于 2015-01-23T20:57:16.990 回答