当前位置:  开发笔记 > 编程语言 > 正文

你如何在JavaScript中找到调用函数?

如何解决《你如何在JavaScript中找到调用函数?》经验,为你挑选了18个好方法。

回顾(并使其更清晰)......

这段代码:

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

相当于:

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

显然第一位更容易携带,因为你可以更改函数的名称,比如从"Hello"到"Ciao"​​,并且仍然可以完成所有工作.

在后者中,如果您决定重构被调用函数(Hello)的名称,则必须更改其所有出现次数:(



1> Greg Hewgill..:
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`将获取函数的名称.
"'调用者','被调用者'和'参数'属性可能无法在严格模式函数或调用它们的参数对象上访问" - 它们在ES5中被弃用并在严格模式下被删除.
自2011年列出此帖后,此方法已过时.首选方法现为Function.caller(截至2015年).
`arguments`可以在严格模式下从函数中访问,弃用它是愚蠢的.只是不是来自外部的function.arguments.此外,如果您有一个命名参数,则它的arguments [i]形式将不会跟踪您对函数内的命名版本所做的更改.
只有在不使用严格模式时才会起作用.所以删除''use strict';`可能有帮助.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller Function.caller:非标准此功能是非标准的,不在标准轨道上.不要在面向Web的生产站点上使用它:它不适用于每个用户.实现之间可能存在很大的不兼容性,并且行为可能在将来发生变化.
`Function.caller`对大多数ES6都不起作用:对于严格模式,它是[禁止扩展](http://www.ecma-international.org/ecma-262/6.0/#sec-forbidden-extensions)函数,如果已定义,则必须在访问时抛出.ES6 [模块始终处于严格模式](http://www.ecma-international.org/ecma-262/6.0/#sec-strict-mode-code).[Chrome的V8实现了这一点](https://medium.com/@bmeurer/function-caller-considered-harmful-45f06916c907); 只有草率模式功能有"来电".这是[出于安全原因](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode).
有趣,但我可以让它只在IE(6)中工作.它在FF3,Opera 9,Safari 3中不起作用......
任何想要在Typescript和Angular等框架中也能使用的更现代的解决方案的人,请使用`console.log((new Error).stack);`。

2> Mariano Desa..:

堆栈跟踪

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

但并非所有新闻都是好的:

    获取堆栈跟踪非常慢,所以要小心(请阅读此内容以获取更多信息).

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

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

    谷歌浏览... kls.Hello ( ...器会发出警报,但大多数浏览器都会在关键字后面找到一个功能名称function,并将其视为匿名功能.Klass如果您没有kls为该功能提供名称,那么甚至Chrome都无法使用该名称.

    顺便说一句,您可以将选项传递给函数printStackTrace,{guess: true}但我没有找到任何真正的改进.

    并非所有浏览器都提供相同的信息.即参数,代码列等.


来电者功能名称

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

arguments.callee.caller.name

但请注意,此名称将是function关键字后面的名称.我发现在没有获得整个功能的代码的情况下,没有办法(甚至在谷歌浏览器上)获得更多.


来电者功能代码

并总结其余的最佳答案(由Pablo Cabrera,nourdine和Greg Hewgill撰写).您可以使用的唯一跨浏览器和非常安全的事情是:

arguments.callee.caller.toString();

这将显示调用者函数的代码.遗憾的是,这对我来说还不够,这就是为什么我给你提供StackTrace和调用函数名称的提示(虽然它们不是跨浏览器).



3> nourdine..:

回顾(并使其更清晰)......

这段代码:

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

相当于:

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

显然第一位更容易携带,因为你可以更改函数的名称,比如从"Hello"到"Ciao"​​,并且仍然可以完成所有工作.

在后者中,如果您决定重构被调用函数(Hello)的名称,则必须更改其所有出现次数:(


arguments.callee.caller在Chrome 25.0.1364.5 dev上始终为null

4> ale5000..:

您可以获得完整的堆栈跟踪:

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

直到来电者null.

注意:它会导致递归函数无限循环.


很抱歉迟到的回复,但我之前没有看过你的评论; 仅对于递归情况它不起作用,在其他情况下它应该工作.

5> Phil..:

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


这是一个古老的问题……但这绝对是当今最有效的现代方法。

6> 小智..:

我通常(new Error()).stack在Chrome中使用.好消息是,它还为您提供了调用者调用函数的行号.缺点是它将堆栈的长度限制为10,这就是我首先来到这个页面的原因.

(我在执行期间使用它来在低级构造函数中收集callstack,以便稍后查看和调试,因此设置断点是没有用的,因为它会被命中数千次)


当''使用严格'时,这是我唯一可以工作的东西;`就位了.给我我需要的信息 - 谢谢!
关于堆栈长度的限制......您可以使用"Error.stackTraceLimit = Infinity"更改它.

7> gumkins..:

如果你不打算在IE <11中运行它,那么console.trace()就适合了.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4



8> Greg..:

您可以使用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


在严格模式下似乎不可能这样吗?`无法访问严格模式函数的调用者属性

9> Pablo Cabrer..:

使用*arguments.callee.caller起来更安全,因为arguments.caller弃用 ...


`arguments.callee`在ES5中也已弃用,并在严格模式下删除.
还有其他选择吗?编辑:`arguments.callee`是解决问题的一个糟糕的解决方案,现在已经得到了更好的解决https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments/callee

10> Shadow2531..:
function Hello() {
    alert(Hello.caller);
}



11> inorganik..:

我会这样做:

function Hello() {
  console.trace();
}



12> QueueHammer..:

看起来这是一个相当解决的问题,但我最近发现被调用者不允许进入'严格模式',所以对于我自己的用途,我写了一个类,它将从它被调用的地方获取路径.它是一个小助手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('.');
  };
}



13> 小智..:

尝试访问:

arguments.callee.caller.name



14> Prasanna..:

只需控制台记录您的错误堆栈.然后你就可以知道你是如何被召唤的

const hello = () => {
  console.log(new Error('I was called').stack)
}

const sello = () => {
  hello()
}

sello()


15> Rovanion..:
2018更新

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();
}());


16> bladnman..:

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

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

我测试过这是chrome,safari和IE(10和8).工作良好.只有一个功能很重要,所以如果你被大小提琴吓到了,请阅读下面的内容.

注意:这个小提琴中有相当数量的我自己的"样板".你可以删除所有这些并使用split's,如果你愿意.这只是我依赖的一套超安全的"功能".

还有一个"JSFiddle"模板,我用它来制作许多小提琴,只需快速摆弄即可.



17> JoolzCheat..:

如果您只想要函数名而不是代码,并且想要一个独立于浏览器的解决方案,请使用以下命令:

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



18> Pablo Arment..:

只是想让你知道,在PhoneGap/Androidname似乎并没有起作用.但是arguments.callee.caller.toString()会做到这一点.

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有