function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
有没有办法找出调用堆栈?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
有没有办法找出调用堆栈?
Answers:
function Hello()
{
alert("caller is " + Hello.caller);
}
请注意,此功能是非标准功能,来自Function.caller
:
非标准
此功能是非标准的,不在标准范围内。请勿在面向Web的生产站点上使用它:它不适用于每个用户。实现之间也可能存在很大的不兼容性,并且行为将来可能会改变。
以下是2008年的旧答案,现代Javascript不再支持该答案:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
将获得函数的名称。
'use strict';
可能会有所帮助。
arguments
可以在严格模式下从功能内访问该函数,不建议这样做。只是不是来自外部的function.arguments。另外,如果您有命名实参,则其中的arguments [i]形式将不会跟踪您对该函数内的命名版本所做的更改。
您可以使用浏览器特定的代码找到整个堆栈跟踪。好事情是有人已经做到了 ; 这是GitHub上的项目代码。
但并非所有新闻都是好消息:
这实在是太慢得到堆栈跟踪,所以要小心(读这更多)。
您将需要定义函数名称以使堆栈跟踪清晰易读。因为如果您有这样的代码:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
Google Chrome ... kls.Hello ( ...
浏览器会发出警报,但是大多数浏览器会在关键字之后加上一个函数名称function
,并将其视为匿名函数。Klass
如果您不给kls
函数指定名称,Chrome甚至无法使用该名称。
顺便说一句,您可以将选项传递给函数printStackTrace,{guess: true}
但是这样做并没有发现任何真正的改进。
并非所有浏览器都为您提供相同的信息。也就是说,参数,代码列等。
顺便说一句,如果您只想要调用者函数的名称(在大多数浏览器中,而不是IE),则可以使用:
arguments.callee.caller.name
但请注意,此名称将是function
关键字之后的名称。我发现没有方法(即使在Google Chrome上)也无法获得全部功能的代码。
并总结其余的最佳答案(由Pablo Cabrera,nourdine和Greg Hewgill撰写)。您可以使用的唯一跨浏览器和真正安全的东西是:
arguments.callee.caller.toString();
它将显示调用者函数的代码。可悲的是,这对我来说还不够,这就是为什么我为您提供有关StackTrace和调用方函数Name(尽管它们不是跨浏览器)的提示的原因。
Function.caller
但是,无法在严格模式下工作。
我知道您提到“用Java语言编写”,但是如果目的是调试,我认为仅使用浏览器的开发人员工具会更容易。在Chrome中是这样的: 只需将调试器放在要调查堆栈的位置即可。
回顾(并使其更加清晰)...
此代码:
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
。
注意:这会在递归函数上造成无限循环。
我通常(new Error()).stack
在Chrome中使用。令人高兴的是,这还为您提供了调用方调用该函数的行号。缺点是它将堆栈的长度限制为10,这就是为什么我首先来到此页面的原因。
(我正在使用它在执行期间收集低级构造函数中的调用栈,以供日后查看和调试,因此设置断点是没有用的,因为它会被击中数千次)
'use strict';
到位后唯一可以工作的东西。给我我需要的信息-谢谢!
如果您不打算在IE <11中运行它,那么console.trace()将很适合。
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
您可以使用Function.Caller来获取调用函数。使用arguments.caller的旧方法被认为已过时。
以下代码说明了其用法:
function Hello() { return Hello.caller;}
Hello2 = function NamedFunc() { return NamedFunc.caller; };
function main()
{
Hello(); //both return main()
Hello2();
}
有关过时的arguments.caller的说明:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/caller
请注意Function.caller是非标准的:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Cannot access caller property of a strict mode function
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
*arguments.callee.caller
由于arguments.caller
已弃用,因此使用起来更安全...
arguments.callee
在ES5中也已弃用,并在严格模式下将其删除。
arguments.callee
是一个糟糕的解决一个问题,即现在已经较好地解决了developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
看来这是一个已解决的问题,但是我最近发现,在“严格模式”下不允许被调用者,因此我自己编写了一个类,该类将从其调用位置获取路径。它是小型帮助程序库的一部分,如果要独立使用代码,请更改用于返回调用方堆栈跟踪的偏移量(使用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('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
在控制台中不适用于我(尚未在文件中尝试过),但似乎有一个合理的想法。无论如何都应该提高可见度。
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)。工作良好。只有1个功能很重要,因此,如果您对大提琴感到害怕,请阅读以下内容。
注意:在这个小提琴中有很多我自己的“样板”。您可以删除所有这些,并根据需要使用split的。这只是我要依赖的一组超安全功能。
我那里还有一个“ JSFiddle”模板,我用它来简单地快速摆弄许多小提琴。
String.prototype.trim = trim;
如果只需要函数名称而不是代码,并且想要独立于浏览器的解决方案,请使用以下命令:
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()
会成功的。
在这里,除以外的所有内容都通过RegExp 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>
这是一个获取完整stacktrace的函数:
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
heystewart的答案和JiarongWu的答案都提到Error
对象可以访问stack
。
这是一个例子:
function main() {
Hello();
}
function Hello() {
var stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
// N.B. 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();
不同的浏览器以不同的字符串格式显示堆栈:
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中,堆栈是未定义的-您必须抛出一个真正的异常才能检索堆栈。
结论:可以使用对象stack
中的“主”来确定“ Hello”的调用方 Error
。实际上,在callee
/ caller
方法不起作用的情况下它将起作用。它还将显示上下文,即源文件和行号。但是,需要付出很多努力才能使解决方案跨平台。
请注意,您不能在Node.js中使用Function.caller,而应使用caller-id包。例如:
var callerId = require('caller-id');
function foo() {
bar();
}
function bar() {
var caller = callerId.getData();
/*
caller = {
typeName: 'Object',
functionName: 'foo',
filePath: '/path/of/this/file.js',
lineNumber: 5,
topLevelFlag: true,
nativeFlag: false,
evalFlag: false
}
*/
}
尝试以下代码:
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中为我工作。
arguments.callee
已弃用很多年了。
解决此问题的另一种方法是简单地将调用函数的名称作为参数传递。
例如:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
现在,您可以像下面这样调用该函数:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
我的示例使用对功能名称的硬编码检查,但是您可以轻松地使用switch语句或其他逻辑来完成所需的操作。
据我所知,我们有2种方法可以从这样的特定来源获得此信息-
function whoCalled()
{
if (arguments.caller == null)
console.log('I was called from the global scope.');
else
console.log(arguments.caller + ' called me!');
}
function myFunc()
{
if (myFunc.caller == null) {
return 'The function was called from the top!';
}
else
{
return 'This function\'s caller was ' + myFunc.caller;
}
}
想你有你的答案:)。
为什么上述所有解决方案都像一门火箭科学。同时,它不应比此片段更复杂。此人的所有功劳
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)]
我正在尝试解决这个问题以及当前对这个问题的悬赏。
赏金要求以严格模式获得调用方,而我能看到的唯一方法是引用在外部声明的函数严格模式。
例如,以下内容是非标准的,但已通过之前(29/03/2016)和当前(2018年8月1日)版本的Chrome,Edge和Firefox进行了测试。
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);
}
main();
如果您出于某种原因确实需要此功能,并且希望它与跨浏览器兼容,而又不必担心严格的要求并向前兼容,则可以传递以下引用:
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
}
我认为以下代码段可能会有所帮助:
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