回顾(并使其更清晰)......
这段代码:
function Hello() { alert("caller is " + arguments.callee.caller.toString()); }
相当于:
function Hello() { alert("caller is " + Hello.caller.toString()); }
显然第一位更容易携带,因为你可以更改函数的名称,比如从"Hello"到"Ciao",并且仍然可以完成所有工作.
在后者中,如果您决定重构被调用函数(Hello)的名称,则必须更改其所有出现次数:(
function Hello() { alert("caller is " + Hello.caller); }
请注意,此功能不标准,来自Function.caller
:
非标准
此功能是非标准的,不在标准轨道上.不要在面向Web的生产站点上使用它:它不适用于每个用户.实现之间可能存在很大的不兼容性,并且行为可能在将来发生变化.
以下是2008年的旧答案,现代Javascript不再支持:
function Hello() { alert("caller is " + arguments.callee.caller.toString()); }
您可以使用特定于浏览器的代码查找整个堆栈跟踪.好事是有人已经做到了 ; 这是GitHub上的项目代码.
但并非所有新闻都是好的:
获取堆栈跟踪非常慢,所以要小心(请阅读此内容以获取更多信息).
您需要将堆栈跟踪的函数名称定义为清晰.因为如果您有这样的代码:
var Klass = function kls() { this.Hello = function() { alert(printStackTrace().join('\n\n')); }; } new Klass().Hello();
谷歌浏览... kls.Hello ( ...
器会发出警报,但大多数浏览器都会在关键字后面找到一个功能名称function
,并将其视为匿名功能.Klass
如果您没有kls
为该功能提供名称,那么甚至Chrome都无法使用该名称.
顺便说一句,您可以将选项传递给函数printStackTrace,{guess: true}
但我没有找到任何真正的改进.
并非所有浏览器都提供相同的信息.即参数,代码列等.
顺便说一句,如果您只想要调用函数的名称(在大多数浏览器中,但不是IE),您可以使用:
arguments.callee.caller.name
但请注意,此名称将是function
关键字后面的名称.我发现在没有获得整个功能的代码的情况下,没有办法(甚至在谷歌浏览器上)获得更多.
并总结其余的最佳答案(由Pablo Cabrera,nourdine和Greg Hewgill撰写).您可以使用的唯一跨浏览器和非常安全的事情是:
arguments.callee.caller.toString();
这将显示调用者函数的代码.遗憾的是,这对我来说还不够,这就是为什么我给你提供StackTrace和调用函数名称的提示(虽然它们不是跨浏览器).
回顾(并使其更清晰)......
这段代码:
function Hello() { alert("caller is " + arguments.callee.caller.toString()); }
相当于:
function Hello() { alert("caller is " + Hello.caller.toString()); }
显然第一位更容易携带,因为你可以更改函数的名称,比如从"Hello"到"Ciao",并且仍然可以完成所有工作.
在后者中,如果您决定重构被调用函数(Hello)的名称,则必须更改其所有出现次数:(
您可以获得完整的堆栈跟踪:
arguments.callee.caller arguments.callee.caller.caller arguments.callee.caller.caller.caller
直到来电者null
.
注意:它会导致递归函数无限循环.
我知道你提到"在Javascript中",但如果目的是调试,我认为使用浏览器的开发者工具会更容易.这就是它在Chrome中的外观: 只需将调试器放在要调查堆栈的位置即可.
我通常(new Error()).stack
在Chrome中使用.好消息是,它还为您提供了调用者调用函数的行号.缺点是它将堆栈的长度限制为10,这就是我首先来到这个页面的原因.
(我在执行期间使用它来在低级构造函数中收集callstack,以便稍后查看和调试,因此设置断点是没有用的,因为它会被命中数千次)
如果你不打算在IE <11中运行它,那么console.trace()就适合了.
function main() { Hello(); } function Hello() { console.trace() } main() // Hello @ VM261:9 // main @ VM261:4
您可以使用Function.Caller来获取调用函数.使用argument.caller的旧方法被认为是过时的.
以下代码说明了它的用法:
function Hello() { return Hello.caller;} Hello2 = function NamedFunc() { return NamedFunc.caller; }; function main() { Hello(); //both return main() Hello2(); }
关于过时的argument.caller的注释:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller
请注意,Function.caller是非标准的:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
使用*arguments.callee.caller
起来更安全,因为arguments.caller
已弃用 ...
function Hello() { alert(Hello.caller); }
我会这样做:
function Hello() { console.trace(); }
看起来这是一个相当解决的问题,但我最近发现被调用者不允许进入'严格模式',所以对于我自己的用途,我写了一个类,它将从它被调用的地方获取路径.它是一个小助手lib的一部分,如果你想独立使用代码,可以更改用于返回调用者堆栈跟踪的偏移量(使用1而不是2)
function ScriptPath() { var scriptPath = ''; try { //Throw an error to generate a stack trace throw new Error(); } catch(e) { //Split the stack trace into each line var stackLines = e.stack.split('\n'); var callerIndex = 0; //Now walk though each line until we find a path reference for(var i in stackLines){ if(!stackLines[i].match(/http[s]?:\/\//)) continue; //We skipped all the lines with out an http so we now have a script reference //This one is the class constructor, the next is the getScriptPath() call //The one after that is the user code requesting the path info (so offset by 2) callerIndex = Number(i) + 2; break; } //Now parse the string for each section we want to return pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/); } this.fullPath = function() { return pathParts[1]; }; this.path = function() { return pathParts[2]; }; this.file = function() { return pathParts[3]; }; this.fileNoExt = function() { var parts = this.file().split('.'); parts.length = parts.length != 1 ? parts.length - 1 : 1; return parts.join('.'); }; }
尝试访问:
arguments.callee.caller.name
只需控制台记录您的错误堆栈.然后你就可以知道你是如何被召唤的
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
caller
在严格模式下被禁止。这是使用(非标准)Error
堆栈的替代方法。
以下功能在Firefox 52和Chrome 61-71中似乎能胜任工作,尽管其实现方式对两种浏览器的日志记录格式进行了很多假设,并且应谨慎使用,因为它会引发异常并可能执行两个正则表达式匹配之前完成。
'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;
function fnName(str) {
const regexResult = fnNameMatcher.exec(str);
return regexResult[1] || regexResult[2];
}
function log(...messages) {
const logLines = (new Error().stack).split('\n');
const callerName = fnName(logLines[1]);
if (callerName !== null) {
if (callerName !== 'log') {
console.log(callerName, 'called log with:', ...messages);
} else {
console.log(fnName(logLines[2]), 'called log with:', ...messages);
}
} else {
console.log(...messages);
}
}
function foo() {
log('hi', 'there');
}
(function main() {
foo();
}());
我想在这里添加我的小提琴:
http://jsfiddle.net/bladnman/EhUm3/
我测试过这是chrome,safari和IE(10和8).工作良好.只有一个功能很重要,所以如果你被大小提琴吓到了,请阅读下面的内容.
注意:这个小提琴中有相当数量的我自己的"样板".你可以删除所有这些并使用split's,如果你愿意.这只是我依赖的一套超安全的"功能".
还有一个"JSFiddle"模板,我用它来制作许多小提琴,只需快速摆弄即可.
如果您只想要函数名而不是代码,并且想要一个独立于浏览器的解决方案,请使用以下命令:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
请注意,如果没有调用函数,上面将返回错误,因为数组中没有[1]元素.要解决此问题,请使用以下内容:
var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);
只是想让你知道,在PhoneGap/Android上name
似乎并没有起作用.但是arguments.callee.caller.toString()
会做到这一点.