你如何findJavaScript中的调用者函数?

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

有没有办法找出调用堆栈呢?

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

请注意,此function是不标准的 ,从Function.caller

非标
这个function是非标准的,不在标准轨道上。 不要在面向Web的生产站点上使用它:它不适用于每个用户。 实现之间也可能存在大的不兼容性,并且行为在未来可能会改变。


以下是2008年的旧答案,现在的Javascript已经不再支持这个答案了:

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

堆栈跟踪

您可以使用浏览器特定的代码find整个堆栈跟踪。 好的是有人已经做到了 ; 这里是GitHub上的项目代码 。

但并非所有的消息都是好的:

  1. 得到堆栈跟踪非常慢,所以要小心(阅读这个更多)。

  2. 您将需要为堆栈跟踪定义函数名称以便清晰。 因为如果你有这样的代码:

     var Klass = function kls() { this.Hello = function() { alert(printStackTrace().join('\n\n')); }; } new Klass().Hello(); 

    谷歌浏览器会提醒你... kls.Hello ( ...但是大多数浏览器会在关键字function后面看到一个函数名,并将其视为一个匿名函数,甚至Chrome也不能使用Klass名字不要给名字kls的function。

    顺便说一句,你可以传递给函数printStackTrace的选项{guess: true}但我没有find任何真正的改善。

  3. 并非所有浏览器都能提供相同的信息。 也就是参数,代码栏等


调用者函数名称

顺便说一下,如果您只需要调用者函数的名称(在大多数浏览器中,而不是IE),则可以使用:

 arguments.callee.caller.name 

但是请注意,这个名字将是function关键字之后的名字。 我发现没有办法(甚至在谷歌浏览器)得到更多的,而没有得到整个function的代码。


来电function码

并总结其余的最好的答案(巴勃罗·卡夫雷拉,nourdine和格雷格·休伊尔)。 唯一可以使用的跨浏览器和安全的东西是:

 arguments.callee.caller.toString(); 

这将显示调用者函数的代码 。 可悲的是,这对我来说是不够的,这就是为什么我给你提供StackTrace和调用者函数Name(尽pipe它们不是跨浏览器)的提示。

回顾(并使其更清楚)…

这个代码:

 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

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

我知道你提到“在Javascript中”,但如果目的是debugging,我认为使用浏览器的开发工具更容易。 这是它在Chrome中的外观: 在这里输入图像描述 只要将debugging器放在要调查堆栈的位置即可。

您可以使用Function.Caller来获取调用函数。 使用argument.caller的旧方法被认为是过时的。

以下代码说明了它的用法:

 function Hello() { return Hello.caller;} Hello2 = function NamedFunc() { return NamedFunc.caller; }; function main() { Hello(); //both return main() Hello2(); } 

关于过时的参数说明: 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

我通常在Chrome中使用(new Error()).stack 。 好的是,这也给你调用者调用函数的行号。 缺点是它限制了堆栈的长度为10,这就是为什么我首先来到这个页面。

(我正在使用它来在执行过程中收集低级构造函数中的调用堆栈,以便稍后查看和debugging,因此设置断点不会被使用,因为它会被命中几千次)

 function Hello() { alert(Hello.caller); } 

使用*arguments.callee.caller更安全,因为arguments.caller已被弃用

看起来这是一个相当不错的问题,但是我最近发现被调用者不能在“严格模式”下使用,所以对于我自己的使用,我写了一个类,它会从调用它的地方得到path。 它是一个小的帮助器lib的一部分,如果你想使用代码独立更改用于返callback用者的堆栈跟踪的偏移量(使用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 

如果你不打算在IE中运行它,那么console.trace()会适合。

 function main() { Hello(); } function Hello() { console.trace() } main() // Hello @ VM261:9 // main @ VM261:4 

如果您只想使用函数名称而不是代码,并且希望独立于浏览器的解决scheme,请使用以下命令:

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

我想在这里添加我的小提琴:

http://jsfiddle.net/bladnman/EhUm3/

我testing了这是铬,Safari和IE(10和8)。 工作正常。 只有1个重要的function,所以如果你被大提琴吓到了,请看下面。

注意:这个小提琴里有我自己的“样板”。 你可以删除所有这些,如果你喜欢,可以使用split。 这只是一个超安全的“我所依赖的一系列function。

在那里还有一个“JSFiddle”模板,我使用了许多小提琴来快速摆弄。

只是想让你知道,在PhoneGap / Androidname似乎并没有工作。 但arguments.callee.caller.toString()将做的伎俩。

在这里,除了functionname所有东西都是从caller.toString()去除的。

 <!DOCTYPE html> <meta charset="UTF-8"> <title>Show the callers name</title><!-- This validates as html5! --> <script> main(); function main() { Hello(); } function Hello(){ var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,''); name = name.replace(/\s/g,''); if ( typeof window[name] !== 'function' ) alert ("sorry, the type of "+name+" is "+ typeof window[name]); else alert ("The name of the "+typeof window[name]+" that called is "+name); } </script> 

这里是一个函数来获得完整的堆栈跟踪 :

 function stacktrace() { var f = stacktrace; var stack = 'Stack trace:'; while (f) { stack += '\n' + f.name; f = f.caller; } return stack; } 

试试下面的代码:

 function getStackTrace(){ var f = arguments.callee; var ret = []; var item = {}; var iter = 0; while ( f = f.caller ){ // Initialize item = { name: f.name || null, args: [], // Empty array = no arguments passed callback: f }; // Function arguments if ( f.arguments ){ for ( iter = 0; iter<f.arguments.length; iter++ ){ item.args[iter] = f.arguments[iter]; } } else { item.args = null; // null = argument listing not supported } ret.push( item ); } return ret; } 

在Firefox-21和Chromium-25中为我工作。

据我所知,我们有这样的来源这样的来源2方式 –

  1. 包含arguments.caller

     function whoCalled() { if (arguments.caller == null) console.log('I was called from the global scope.'); else console.log(arguments.caller + ' called me!'); } 
  2. Function.caller

     function myFunc() { if (myFunc.caller == null) { return 'The function was called from the top!'; } else { return 'This function\'s caller was ' + myFunc.caller; } } 

想你有你的答案:)。

我试图解决这个问题和目前的赏金。

赏金要求调用者在严格模式下获得,我唯一可以看到的是通过引用严格模式之外声明的函数。

例如,以下是非标准的,但已经通过Chrome,Edge和Firefox的当前版本(2016/3/29)进行了testing:

 function caller() { return caller.caller.caller; } 'use strict'; function main() { // Original question: Hello(); // Bounty question: (function() { console.log('Anonymous function called by ' + caller().name); })(); } function Hello() { // How do you find out the caller function is 'main'? console.log('Hello called by ' + caller().name); } 

为什么上面的所有解决scheme看起来像火箭科学? 同时,它不应该比这个片段更复杂。 所有学分给这个家伙

你如何findJavaScript中的调用者函数?

 var stackTrace = function() { var calls = []; var caller = arguments.callee.caller; for (var k = 0; k < 10; k++) { if (caller) { calls.push(caller); caller = caller.caller; } } return calls; }; // when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content // [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)] 

如果你真的需要这些function,并希望它是跨浏览器兼容,而不是担心严格的东西,并向前兼容,然后通过这个参考:

 function main() { Hello(this); } function Hello(caller) { // caller will be the object that called Hello. boom like that... // you can add an undefined check code if the function Hello // will be called without parameters from somewhere else } 

解决这个问题的另一种方法是简单地将调用函数的名称作为parameter passing。

例如:

 function reformatString(string, callerName) { if (callerName === "uid") { string = string.toUpperCase(); } return string; } 

现在,你可以这样调用函数:

 function uid(){ var myString = "apples"; reformatString(myString, function.name); } 

我的例子使用一个硬编码的函数名称检查,但你可以很容易地使用switch语句或其他逻辑来做你想要的。

我认为下面的代码片可能会有所帮助:

 window.fnPureLog = function(sStatement, anyVariable) { if (arguments.length < 1) { throw new Error('Arguments sStatement and anyVariable are expected'); } if (typeof sStatement !== 'string') { throw new Error('The type of sStatement is not match, please use string'); } var oCallStackTrack = new Error(); console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable); } 

执行代码:

 window.fnPureLog = function(sStatement, anyVariable) { if (arguments.length < 1) { throw new Error('Arguments sStatement and anyVariable are expected'); } if (typeof sStatement !== 'string') { throw new Error('The type of sStatement is not match, please use string'); } var oCallStackTrack = new Error(); console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable); } function fnBsnCallStack1() { fnPureLog('Stock Count', 100) } function fnBsnCallStack2() { fnBsnCallStack1() } fnBsnCallStack2(); 

日志看起来像这样:

 Call Stack: at window.fnPureLog (<anonymous>:8:27) at fnBsnCallStack1 (<anonymous>:13:5) at fnBsnCallStack2 (<anonymous>:17:5) at <anonymous>:20:1 Stock Count: 100 

heystewart的回答和JiarongWu的回答都提到Error对象有权访问stack

这是一个例子:

 function main() { Hello(); } function Hello() { var stack; try { throw new Error(); } catch (e) { stack = e.stack; } // NB stack === "Error\n at Hello ...\n at main ... \n...." var m = stack.match(/.*?Hello.*?\n(.*?)\n/); if (m) { var caller_name = m[1]; console.log("Caller is:", caller_name) } } main();