你如何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上的项目代码 。
但并非所有的消息都是好的:
-
得到堆栈跟踪非常慢,所以要小心(阅读这个更多)。
-
您将需要为堆栈跟踪定义函数名称以便清晰。 因为如果你有这样的代码:
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任何真正的改善。 -
并非所有浏览器都能提供相同的信息。 也就是参数,代码栏等
调用者函数名称
顺便说一下,如果您只需要调用者函数的名称(在大多数浏览器中,而不是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 / Android的name
似乎并没有工作。 但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方式 –
-
包含arguments.caller
function whoCalled() { if (arguments.caller == null) console.log('I was called from the global scope.'); else console.log(arguments.caller + ' called me!'); }
-
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();
- 如何将数据作为表单数据而不是请求有效载荷发布?
- Server.MapPath(“。”),Server.MapPath(“〜”),Server.MapPath(@“\”),Server.MapPath(“/”)。 有什么不同?