function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
有没有办法找出调用堆栈?
请注意,此解决方案已弃用,根据 MDN 文档不应再使用
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
function Hello()
{
alert("caller is " + Hello.caller);
}
请注意,此功能是非标准,来自 Function.caller
:
非标准 此功能是非标准的,不在标准轨道上。不要在面向 Web 的生产站点上使用它:它不适用于每个用户。实现之间也可能存在很大的不兼容性,并且行为可能会在未来发生变化。
以下是 2008 年的旧答案,现代 Javascript 不再支持该答案:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
堆栈跟踪
您可以使用浏览器特定代码找到整个堆栈跟踪。好处是someone already made it;这是project code on GitHub。
但并非所有消息都是好消息:
获取堆栈跟踪真的很慢,所以要小心(阅读更多信息)。您需要定义函数名称以使堆栈跟踪清晰易读。因为如果你有这样的代码: var Klass = function kls() { this.Hello = function() { alert(printStackTrace().join('\n\n')); };新的克拉斯()。你好();谷歌浏览器会提醒 ... kls.Hello ( ... 但大多数浏览器会期望在关键字 function 之后有一个函数名称,并将其视为匿名函数。如果您使用 Klass 名称,甚至 Chrome 都无法使用不要给函数命名 kls。顺便说一下,您可以将选项 {guess: true} 传递给函数 printStackTrace,但这样做并没有发现任何真正的改进。并非所有浏览器都给您相同的信息,即参数、代码列等。
调用函数名称
顺便说一句,如果您只想要调用函数的名称(在大多数浏览器中,但不是 IE),您可以使用:
arguments.callee.caller.name
但请注意,此名称将位于 function
关键字之后。如果不获取整个函数的代码,我没有办法(即使在 Google Chrome 上)获得更多。
调用函数代码
并总结其余的最佳答案(Pablo Cabrera、nourdine 和 Greg Hewgill)。您可以使用的唯一跨浏览器且真正安全的方法是:
arguments.callee.caller.toString();
这将显示调用者函数的代码。遗憾的是,这对我来说还不够,这就是为什么我为您提供有关 StackTrace 和调用函数名称的提示(尽管它们不是跨浏览器)。
Function.caller
Function.caller
不能在严格模式下工作。
我通常在 Chrome 中使用 (new Error()).stack
。好消息是这还为您提供了调用者调用该函数的行号。缺点是它将堆栈的长度限制为 10,这就是我首先来到这个页面的原因。
(我使用它在执行期间收集低级构造函数中的调用堆栈,以便稍后查看和调试,因此设置断点没有用,因为它会被命中数千次)
'use strict';
到位时,这是我唯一可以开始工作的事情。给我我需要的信息——谢谢!
https://i.stack.imgur.com/aBtUp.png
如果你不打算在 IE 中运行它 < 11 然后 console.trace() 将适合。
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
您可以获得完整的堆栈跟踪:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
直到调用者是 null
。
注意:它会导致递归函数无限循环。
回顾一下(并使其更清晰)......
这段代码:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
相当于:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
显然第一位更便于移植,因为您可以更改函数的名称,例如从“Hello”到“Ciao”,仍然可以让整个事情正常工作。
在后者中,如果您决定重构被调用函数的名称(Hello),您将不得不更改它的所有出现:(
在 ES6 和 Strict 模式下,使用以下方式获取 Caller 函数
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
请注意,如果没有调用者或没有先前的堆栈,上述行将引发异常。相应地使用。
要获取被调用者(当前函数名),请使用:
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
.stack?
我会这样做:
function Hello() {
console.trace();
}
您可以使用 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
Cannot access caller property of a strict mode function
看起来这是一个相当已解决的问题,但我最近发现 callee is not allowed in 'strict mode' 所以为了我自己的使用,我编写了一个类,该类将从调用它的位置获取路径。它是 part of a small helper 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('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
对我不起作用(尚未在文件中尝试过),但似乎有一个合理的想法。无论如何都应该投票以提高知名度。
Throw .. catch
是不必要的。有可能通过 let stack =new Error().stack
获得堆栈。
thow ... catch
根据 github.com/stacktracejs/stacktrace.js/blob/master/… 在 IE 浏览器中获取堆栈。
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
相同
heystewart's answer 和 JiarongWu's answer 都提到 Error
对象可以访问 stack
。
这是一个例子:
函数 main() { 你好(); } function Hello() { try { throw new Error(); } catch (err) { 让堆栈 = err.stack; // NB stack === "Error\n at Hello ...\n at main ... \n...." let m = stack.match(/.*?Hello.*?\n(.* ?)\n/); if (m) { 让 caller_name = m[1]; console.log("来电者是:", caller_name); } } } 主要的();
不同的浏览器以不同的字符串格式显示堆栈:
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
对象中的 stack
可以确定“main”是“Hello”的调用者。事实上,它适用于 callee
/ caller
方法不起作用的情况。它还将向您显示上下文,即源文件和行号。但是,需要努力使解决方案跨平台。
使用 *arguments.callee.caller
更安全,因为 arguments.caller
已弃用...
arguments.callee
在 ES5 中也被弃用,并在严格模式下被移除。
arguments.callee
是一个糟糕的解决方案,现在已经得到了更好的解决developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
2018 更新
caller
is forbidden in strict mode。这是使用(非标准)Error
stack 的替代方法。
以下函数似乎在 Firefox 52 和 Chrome 61-71 中完成了这项工作,尽管它的实现对两个浏览器的日志格式做了很多假设,并且应该谨慎使用,因为它会引发异常并可能执行两个正则表达式匹配之前完成。
'使用严格'; 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, '调用日志:', ...messages); } else { console.log(fnName(logLines[2]), '调用记录:', ...messages); } } else { console.log(...messages); } } function foo() { log('hi', 'there'); } (function main() {富();}());
只需控制台记录您的错误堆栈。然后你就可以知道你是怎么被叫到的
const hello = () => { console.log(new Error('我被叫').stack) } const sello = () => { hello() } sello()
我想在这里添加我的小提琴:
http://jsfiddle.net/bladnman/EhUm3/
我测试了这是 chrome、safari 和 IE(10 和 8)。工作正常。只有 1 个功能很重要,所以如果你被大小提琴吓到了,请阅读下文。
注意:这个小提琴中有很多我自己的“样板”。如果您愿意,您可以删除所有这些并使用拆分。这只是我开始依赖的一组“超安全”功能。
那里还有一个“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()
可以解决问题。
在这里,除了 functionname
之外的所有内容都使用 RegExp 从 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>
这是 get full stacktrace 的函数:
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
请注意,您不能在 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 getCaller(functionBack= 0) {
const back = functionBack * 2;
const stack = new Error().stack.split('at ');
const stackIndex = stack[3 + back].includes('C:') ? (3 + back) : (4 + back);
const isAsync = stack[stackIndex].includes('async');
let result;
if (isAsync)
result = stack[stackIndex].split(' ')[1].split(' ')[0];
else
result = stack[stackIndex].split(' ')[0];
return result;
}
我可以在 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"))
试试下面的代码:
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
已成为 deprecated for many years。
解决此问题的另一种方法是简单地将调用函数的名称作为参数传递。
例如:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
现在,您可以像这样调用该函数:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
我的示例使用了对函数名称的硬编码检查,但您可以轻松地使用 switch 语句或其他一些逻辑来执行您想要的操作。
据我所知,我们从这样的给定来源有两种方法-
arguments.caller function whoCalled() { if (arguments.caller == null) console.log('我是从全局范围调用的。'); else console.log(arguments.caller + '打电话给我!'); } Function.caller function myFunc() { if (myFunc.caller == null) { return '函数是从顶部调用的!'; } else { return '这个函数的调用者是 ' + myFunc.caller; } }
认为你有你的答案:)。
为什么上面的所有解决方案看起来都像火箭科学。同时,它不应该比这个片段更复杂。所有功劳归于这个人
How do you find out the caller function in JavaScript?
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)]
我认为以下代码段可能会有所帮助:
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
arguments.callee.caller.name
将获得函数的名称。'use strict';
可能会有所帮助。arguments
可以在严格模式下从函数内部访问,弃用它是愚蠢的。只是不是来自外部的function.arguments。此外,如果您有一个命名参数,它的 arguments[i] 形式将不会跟踪您对函数内的命名版本所做的更改。