Ray*_* Lu 838 javascript callstack
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Run Code Online (Sandbox Code Playgroud)
有没有办法找出调用堆栈?
Gre*_*ill 973
function Hello()
{
alert("caller is " + Hello.caller);
}
Run Code Online (Sandbox Code Playgroud)
请注意,此功能不标准,来自Function.caller:
非标准
此功能是非标准的,不在标准轨道上.不要在面向Web的生产站点上使用它:它不适用于每个用户.实现之间可能存在很大的不兼容性,并且行为可能在将来发生变化.
以下是2008年的旧答案,现代Javascript不再支持:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*nze 149
您可以使用特定于浏览器的代码查找整个堆栈跟踪.好事是有人已经做到了 ; 这是GitHub上的项目代码.
但并非所有新闻都是好的:
获取堆栈跟踪非常慢,所以要小心(请阅读此内容以获取更多信息).
您需要将堆栈跟踪的函数名称定义为清晰.因为如果您有这样的代码:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
Run Code Online (Sandbox Code Playgroud)
谷歌浏览... kls.Hello ( ...器会发出警报,但大多数浏览器都会在关键字后面找到一个功能名称function,并将其视为匿名功能.Klass如果您没有kls为该功能提供名称,那么甚至Chrome都无法使用该名称.
顺便说一句,您可以将选项传递给函数printStackTrace,{guess: true}但我没有找到任何真正的改进.
并非所有浏览器都提供相同的信息.即参数,代码列等.
顺便说一句,如果您只想要调用函数的名称(在大多数浏览器中,但不是IE),您可以使用:
arguments.callee.caller.name
Run Code Online (Sandbox Code Playgroud)
但请注意,此名称将是function关键字后面的名称.我发现在没有获得整个功能的代码的情况下,没有办法(甚至在谷歌浏览器上)获得更多.
并总结其余的最佳答案(由Pablo Cabrera,nourdine和Greg Hewgill撰写).您可以使用的唯一跨浏览器和非常安全的事情是:
arguments.callee.caller.toString();
Run Code Online (Sandbox Code Playgroud)
这将显示调用者函数的代码.遗憾的是,这对我来说还不够,这就是为什么我给你提供StackTrace和调用函数名称的提示(虽然它们不是跨浏览器).
nou*_*ine 52
回顾(并使其更清晰)......
这段代码:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
Run Code Online (Sandbox Code Playgroud)
相当于:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Run Code Online (Sandbox Code Playgroud)
显然第一位更容易携带,因为你可以更改函数的名称,比如从"Hello"到"Ciao",并且仍然可以完成所有工作.
在后者中,如果您决定重构被调用函数(Hello)的名称,则必须更改其所有出现次数:(
ale*_*000 50
您可以获得完整的堆栈跟踪:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Run Code Online (Sandbox Code Playgroud)
直到来电者null.
注意:它会导致递归函数无限循环.
Phi*_*hil 46
我知道你提到"在Javascript中",但如果目的是调试,我认为使用浏览器的开发者工具会更容易.这就是它在Chrome中的外观:
只需将调试器放在要调查堆栈的位置即可.
小智 38
我通常(new Error()).stack在Chrome中使用.好消息是,它还为您提供了调用者调用函数的行号.缺点是它将堆栈的长度限制为10,这就是我首先来到这个页面的原因.
(我在执行期间使用它来在低级构造函数中收集callstack,以便稍后查看和调试,因此设置断点是没有用的,因为它会被命中数千次)
gum*_*ins 31
如果你不打算在IE <11中运行它,那么console.trace()就适合了.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Run Code Online (Sandbox Code Playgroud)
Van*_*gaS 24
在 ES6 和 Strict 两种模式下,使用以下方法获取 Caller 函数
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Run Code Online (Sandbox Code Playgroud)
请注意,如果没有调用者或没有先前的堆栈,上面的行将抛出异常。相应地使用。
要获取被调用者(当前函数名),请使用:
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
Run Code Online (Sandbox Code Playgroud)
Gre*_*reg 21
您可以使用Function.Caller来获取调用函数.使用argument.caller的旧方法被认为是过时的.
以下代码说明了它的用法:
function Hello() { return Hello.caller;}
Hello2 = function NamedFunc() { return NamedFunc.caller; };
function main()
{
Hello(); //both return main()
Hello2();
}
Run Code Online (Sandbox Code Playgroud)
关于过时的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
Pab*_*era 18
使用*arguments.callee.caller起来更安全,因为arguments.caller已弃用 ...
Sha*_*531 18
function Hello() {
alert(Hello.caller);
}
Run Code Online (Sandbox Code Playgroud)
ino*_*nik 18
我会这样做:
function Hello() {
console.trace();
}
Run Code Online (Sandbox Code Playgroud)
Que*_*mer 16
看起来这是一个相当解决的问题,但我最近发现被调用者不允许进入'严格模式',所以对于我自己的用途,我写了一个类,它将从它被调用的地方获取路径.它是一个小助手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('.');
};
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*uan 16
heystewart 的回答和JiarongWu 的回答都提到Error对象可以访问stack.
下面是一个例子:
function main() {
Hello();
}
function Hello() {
var stack = new Error().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();Run Code Online (Sandbox Code Playgroud)
不同的浏览器以不同的字符串格式显示堆栈:
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)
Run Code Online (Sandbox Code Playgroud)
大多数浏览器会将堆栈设置为var stack = (new Error()).stack. 在 Internet Explorer 中,堆栈将是未定义的 - 您必须抛出一个真正的异常来检索堆栈。
结论:这是可能的,以确定“主”是使用呼叫者为“Hello” stack的Error对象。事实上,它会在callee/caller方法不起作用的情况下起作用。它还会显示上下文,即源文件和行号。然而,需要努力使解决方案跨平台。
小智 11
尝试访问:
arguments.callee.caller.name
Run Code Online (Sandbox Code Playgroud)
Pra*_*nna 11
只需控制台记录您的错误堆栈.然后你就可以知道你是如何被召唤的
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()Run Code Online (Sandbox Code Playgroud)
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();
}());Run Code Online (Sandbox Code Playgroud)
我想在这里添加我的小提琴:
http://jsfiddle.net/bladnman/EhUm3/
我测试过这是chrome,safari和IE(10和8).工作良好.只有一个功能很重要,所以如果你被大小提琴吓到了,请阅读下面的内容.
注意:这个小提琴中有相当数量的我自己的"样板".你可以删除所有这些并使用split's,如果你愿意.这只是我依赖的一套超安全的"功能".
还有一个"JSFiddle"模板,我用它来制作许多小提琴,只需快速摆弄即可.
如果您只想要函数名而不是代码,并且想要一个独立于浏览器的解决方案,请使用以下命令:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
Run Code Online (Sandbox Code Playgroud)
请注意,如果没有调用函数,上面将返回错误,因为数组中没有[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]);
Run Code Online (Sandbox Code Playgroud)
小智 5
在这里,除了 之外的所有内容都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>
Run Code Online (Sandbox Code Playgroud)
请注意,您不能在 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
}
*/
}
Run Code Online (Sandbox Code Playgroud)
使用Error.stack属性是纯 JavaScript 获取调用者函数名称(或完整调用堆栈)的通用解决方案。但在长堆栈或频繁调用的情况下,它可能会占用大量资源,因为您string通过慢速trim,split或match方法来操作对象。
CallSite更好的解决方案是直接使用以下命令访问堆栈的项目数组prepareStackTrace:
function getCallerName() {
// Get stack array
const orig = Error.prepareStackTrace;
Error.prepareStackTrace = (error, stack) => stack;
const { stack } = new Error();
Error.prepareStackTrace = orig;
const caller = stack[2];
return caller ? caller.getFunctionName() : undefined;
}
Run Code Online (Sandbox Code Playgroud)
它适用于类、箭头和异步函数等,例如:
function hello() {
console.log(getCallerName());
}
class A {
constructor() {
console.log(getCallerName());
}
hello() {
console.log(getCallerName());
}
}
function main() {
hello(); // Prints: main
const a = new A(); // Prints: main
a.hello(); // Prints: main
}
main();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
424180 次 |
| 最近记录: |