function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

有办法找到调用堆栈吗?


当前回答

我通常使用(new Error())。堆叠在Chrome。 好处是,这还提供了调用者调用函数的行号。缺点是它将堆栈的长度限制在10,这就是为什么我首先来到这个页面。

(我使用这个在执行期间收集低级构造函数中的调用栈,以便稍后查看和调试,所以设置断点是没有用的,因为它将被命中数千次)

其他回答

heystewart和JiarongWu的回答都提到了Error对象可以访问堆栈。

这里有一个例子:

函数main() { 你好(); } 函数Hello() { 尝试{ throw new Error(); } catch (err) { Let stack = err.stack; // N.B. stack === "Error\n at Hello…\n at main…\ n……” let m = stack.match(/.*?Hello.*?\n(.*?)\n/); 如果(m) { 让caller_name = m[1]; console.log("Caller is:", caller_name); } } } main ();

不同的浏览器以不同的字符串格式显示堆栈:

Safari  : Caller is: main@https://stacksnippets.net/js:14:8
Firefox : Caller is: main@https://stacksnippets.net/js:14:3
Chrome  : Caller is:     at main (https://stacksnippets.net/js:14:3)
IE Edge : Caller is:    at main (https://stacksnippets.net/js:14:3)
IE      : Caller is:    at main (https://stacksnippets.net/js:14:3)

大多数浏览器会使用var stack = (new Error()).stack来设置堆栈。在Internet Explorer中,堆栈是未定义的——你必须抛出一个真正的异常来检索堆栈。

结论:使用Error对象中的堆栈可以确定“main”是“Hello”的调用者。事实上,它可以在被调用方/调用方方法不起作用的情况下工作。它还会显示上下文,即源文件和行号。然而,要使解决方案跨平台还需要努力。

我可以在2021年使用这些,并获得从调用者函数开始的堆栈:

1. console.trace();
2. console.log((new Error).stack)

// do the same as #2 just with better view
3. console.log((new Error).stack.split("\n")) 

试着访问这个:

arguments.callee.caller.name

你可以得到完整的堆栈跟踪:

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

直到调用者为空。

注意:它会导致递归函数的无限循环。

概括一下(并说得更清楚)…

这段代码:

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

等价于:

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

显然,第一部分更容易移植,因为你可以改变函数的名字,从“Hello”说成“Ciao”,但仍然可以让整个程序正常工作。

在后一种情况下,如果你决定重构被调用函数的名称(Hello),你将不得不改变它的所有出现: