我可以获取JavaScript中当前正在运行的函数的名称吗?


184

是否有可能做到这一点:

myfile.js:
function foo() {
    alert(<my-function-name>);
    // pops-up "foo"
    // or even better: "myfile.js : foo"
}

我的堆栈中有Dojo和jQuery框架,因此,如果这两个框架都使它变得更容易,它们将可用。

Answers:


196

在ES5及更高版本中,无法访问该信息。

在旧版JS中,您可以使用来获得它arguments.callee

但是,您可能必须解析名称,因为它可能包括一些额外的垃圾。不过,在某些实现中,您可以使用arguments.callee.name

解析:

function DisplayMyName() 
{
   var myName = arguments.callee.toString();
   myName = myName.substr('function '.length);
   myName = myName.substr(0, myName.indexOf('('));

   alert(myName);
}

来源:Javascript-获取当前函数名称


实际上,实际上是要更加注意您的问题,听起来您可能想要多余的垃圾:)
马特(Matt)2009年

23
@安德鲁-你是对的,我应该这么说。这是对我已添加书签的内容的快速复制/粘贴/清理,而我的疏忽大意。感谢您将其添加到我的帖子中。
Matt

81
打破ES5严格模式。
雷诺斯

4
哦,这就是为什么人们总是在回复速度上击败我。我没想到。
埃里克·雷彭

9
如果您为方法使用对象字面量,但没有实际的方法名称,则它将不能用作参数.callee的作用类似于匿名函数,该函数将不包含任何函数名。您必须确保两次添加该函数名称。看一下这个jsfiddle示例:jsfiddle.net/ncays。但是,与此相关的另一个问题arguments.callee是在严格模式下是不允许的。
hellatan

75

对于非匿名函数

function foo()
{ 
    alert(arguments.callee.name)
}

但是如果是错误处理程序,结果将是错误处理程序函数的名称,不是吗?


2
在Chrome浏览器中效果很好。比接受的答案好得多。
B 7年

1
值得记住的是:eslint.org/docs/rules/no-caller >“ JavaScript的未来版本中已弃用,并且在严格模式下ECMAScript 5中禁止使用它们。”
杰里米

45

您所需要的一切都很简单。创建函数:

function getFuncName() {
   return getFuncName.caller.name
}

之后,只要需要,您只需使用:

function foo() { 
  console.log(getFuncName())
}

foo() 
// Logs: "foo"

3
谢谢,这比解析字符串要优雅得多。
modle13'3

1
这似乎是最好的答案!
谢尔盖

完善。那时JS没有像PHP那样具有魔术常数的原生常数……
stamster

Chrome给我一个类型错误,因为调用者不存在属性“名称”。但是,检查显示,此方法有效:function getFuncName() { return getFuncName.name }
Tom Anderson

@TomAnderson与您的更改,您现在得到的名称,getFuncName而不是其调用方的名称。
Mark McKenna

30

根据MDN

警告:第5版ECMAScript(ES5)禁止在严格模式下使用arguments.callee()。通过给函数表达式命名或在函数必须调用自身的地方使用函数声明来避免使用arguments.callee()。

如前所述,这在脚本使用“严格模式”时适用。这主要是出于安全原因,遗憾的是目前没有其他选择。


21

应该这样做:

var fn = arguments.callee.toString().match(/function\s+([^\s\(]+)/);
alert(fn[1]);

对于呼叫者,只需使用caller.toString()


8
这对我有用,但我认为您的正则表达式中有错字。我必须在[
declan 2012年

4
@declan:是的,你是对的。令人惊讶的是,没有人指出在近三年中这个答案一直在这里:-)
Andy E

@AndyE可能没有人指出,因为一旦看到正则表达式,我们就会进入TL; DR模式并寻找其他答案;)
BitTickler

11

这必须归类为“世界上最丑陋的骇客”类别,但是您可以在这里找到。

首先,对我来说,打印当前函数的名称(与其他答案一样)似乎用途有限,因为您已经知道该函数是什么!

但是,找出调用函数的名称对于跟踪函数可能非常有用。这是一个正则表达式,但是使用indexOf大约快三倍:

function getFunctionName() {
    var re = /function (.*?)\(/
    var s = getFunctionName.caller.toString();
    var m = re.exec( s )
    return m[1];
}

function me() {
    console.log( getFunctionName() );
}

me();

冷却溶液,但FYI功能#呼叫者是非标准developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
最大Heiber

如果要从数据库中动态创建当前函数的名称,并且需要在函数内部键入关联到该函数名称的上下文信息,那么知道当前函数的名称就至关重要。
Paul Chernoch

9

这是一种可行的方法:

export function getFunctionCallerName (){
  // gets the text between whitespace for second part of stacktrace
  return (new Error()).stack.match(/at (\S+)/g)[1].slice(3);
}

然后在您的测试中:

import { expect } from 'chai';
import { getFunctionCallerName } from '../../../lib/util/functions';

describe('Testing caller name', () => {

    it('should return the name of the function', () => {
      function getThisName(){
        return getFunctionCallerName();
      }

      const functionName = getThisName();

      expect(functionName).to.equal('getThisName');
    });

  it('should work with an anonymous function', () => {


    const anonymousFn = function (){
      return getFunctionCallerName();
    };

    const functionName = anonymousFn();

    expect(functionName).to.equal('anonymousFn');
  });

  it('should work with an anonymous function', () => {
    const fnName = (function (){
      return getFunctionCallerName();
    })();

    expect(/\/util\/functions\.js/.test(fnName)).to.eql(true);
  });

});

请注意,只有在/ util / functions中,第三项测试才有效


7

getMyName以下代码段中的函数返回调用函数的名称。这是一个hack,它依赖于非标准功能:Error.prototype.stack。请注意,返回的字符串格式Error.prototype.stack在不同的引擎中以不同的方式实现,因此这可能不适用于所有地方:

function getMyName() {
  var e = new Error('dummy');
  var stack = e.stack
                .split('\n')[2]
                // " at functionName ( ..." => "functionName"
                .replace(/^\s+at\s+(.+?)\s.+/g, '$1' );
                return stack
}

function foo(){
  return getMyName()
}

function bar() {
  return foo()
}

console.log(bar())

关于其他的解决方案:arguments.callee 是不是在严格模式下允许的Function.prototype.caller非标准和严格模式不允许的


扩展它以在函数中显示位置并通过以下方式支持匿名函数:.replace(/ ^ \ s + at \ s(。+?)(?:\ s。*:|:)(。*?):(。* ?))?$ / g,'$ 1($ 2:$ 3)')
kofifus

在严格模式下也不允许使用Function.prototype.caller。
fijiaaron

1
即使对于箭头功能也很完美,答案被低估了
郝浩

3

另一个用例可能是在运行时绑定的事件分派器:

MyClass = function () {
  this.events = {};

  // Fire up an event (most probably from inside an instance method)
  this.OnFirstRun();

  // Fire up other event (most probably from inside an instance method)
  this.OnLastRun();

}

MyClass.prototype.dispatchEvents = function () {
  var EventStack=this.events[GetFunctionName()], i=EventStack.length-1;

  do EventStack[i]();
  while (i--);
}

MyClass.prototype.setEvent = function (event, callback) {
  this.events[event] = [];
  this.events[event].push(callback);
  this["On"+event] = this.dispatchEvents;
}

MyObject = new MyClass();
MyObject.setEvent ("FirstRun", somecallback);
MyObject.setEvent ("FirstRun", someothercallback);
MyObject.setEvent ("LastRun", yetanothercallback);

这样做的优点是可以轻松地重用调度程序,并且不必将调度队列作为参数来接收,而是使用调用名称隐式地分配了调度程序...

最后,这里介绍的一般情况是“使用函数名称作为参数,因此您不必显式传递它”,这在许多情况下可能很有用,例如jquery animate()可选回调,或在超时/间隔回调中(即,您仅传递函数名称)。


2

自从提出这个问题以来,当前功能的名称及其获取方式似乎在过去10年中发生了变化。

现在,不是成为一个专业的Web开发人员,不知道所有存在的所有浏览器的所有历史,这是它在2019年chrome浏览器中对我的工作方式:

function callerName() {
    return callerName.caller.name;
}
function foo() {
    let myname = callerName();
    // do something with it...
}

其他一些答案遇到了一些严格的javascript代码等问题。


1

由于您已经编写了一个名为的函数,foo并且知道myfile.js为什么要动态获取此信息?

话虽如此,您可以arguments.callee.toString()在函数内部使用(这是整个函数的字符串表示形式),并用正则表达式列出函数名称的值。

这是一个将吐出自己名字的函数:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}

5
我正在处理错误处理程序,并且想报告调用函数。
sprugman

1

我在这里看到的一些回答的组合。(已在FF,Chrome,IE11中测试)

function functionName() 
{
   var myName = functionName.caller.toString();
   myName = myName.substr('function '.length);
   myName = myName.substr(0, myName.indexOf('('));
   return myName;
}

function randomFunction(){
    var proof = "This proves that I found the name '" + functionName() + "'";
    alert(proof);
}

调用randomFunction()将提醒包含函数名称的字符串。

JS小提琴演示:http//jsfiddle.net/mjgqfhbe/



1

信息为2016年的实际数据。


函数声明的结果

在歌剧中的结果

>>> (function func11 (){
...     console.log(
...         'Function name:',
...         arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
... })();
... 
... (function func12 (){
...     console.log('Function name:', arguments.callee.name)
... })();
Function name:, func11
Function name:, func12

结果在Chrome中

(function func11 (){
    console.log(
        'Function name:',
        arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
})();

(function func12 (){
    console.log('Function name:', arguments.callee.name)
})();
Function name: func11
Function name: func12

结果在NodeJS中

> (function func11 (){
...     console.log(
.....         'Function name:',
.....         arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
... })();
Function name: func11
undefined
> (function func12 (){
...     console.log('Function name:', arguments.callee.name)
... })();
Function name: func12

在Firefox中不起作用。在IE和Edge上未经测试。


函数表达式的结果

结果在NodeJS中

> var func11 = function(){
...     console.log('Function name:', arguments.callee.name)
... }; func11();
Function name: func11

结果在Chrome中

var func11 = function(){
    console.log('Function name:', arguments.callee.name)
}; func11();
Function name: func11

在Firefox,Opera中不起作用。在IE和Edge上未经测试。

笔记:

  1. 匿名功能没有任何意义。
  2. 测试环境

~ $ google-chrome --version
Google Chrome 53.0.2785.116           
~ $ opera --version
Opera 12.16 Build 1860 for Linux x86_64.
~ $ firefox --version
Mozilla Firefox 49.0
~ $ node
node    nodejs  
~ $ nodejs --version
v6.8.1
~ $ uname -a
Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

1
(function f() {
    console.log(f.name);  //logs f
})();

打字稿变体:

function f1() {} 
function f2(f:Function) {
   console.log(f.name);
}

f2(f1);  //Logs f1

请注意,仅在符合ES6 / ES2015的引擎中可用。 有关更多信息


0

这是一个班轮:

    arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '')

像这样:

    function logChanges() {
      let whoami = arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '');
      console.log(whoami + ': just getting started.');
    }

0

这是Igor Ostroumov答案的变体:

如果要将其用作参数的默认值,则需要考虑对“ caller”的第二级调用:

function getFunctionsNameThatCalledThisFunction()
{
  return getFunctionsNameThatCalledThisFunction.caller.caller.name;
}

这将动态地允许在多个功能中实现可重用的实现。

function getFunctionsNameThatCalledThisFunction()
{
  return getFunctionsNameThatCalledThisFunction.caller.caller.name;
}

function bar(myFunctionName = getFunctionsNameThatCalledThisFunction())
{ 
  alert(myFunctionName);
}

// pops-up "foo"
function foo()
{
  bar();
}

function crow()
{
  bar();
}

foo();
crow();

如果您也想要文件名,以下是使用F-3000回答另一个问题的解决方案:

function getCurrentFileName()
{
  let currentFilePath = document.scripts[document.scripts.length-1].src 
  let fileName = currentFilePath.split('/').pop() // formatted to the OP's preference

  return fileName 
}

function bar(fileName = getCurrentFileName(),  myFunctionName = getFunctionsNameThatCalledThisFunction())
{
  alert(fileName + ' : ' + myFunctionName);
}

// or even better: "myfile.js : foo"
function foo()
{
  bar();
}


-7

答案很简短: alert(arguments.callee.name);


12
“ nom”在法语中是“ name”。浏览器的语言版本之间是否会更改此类详细信息?我不会这样。
argyle,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.