【问题标题】:Can I get the name of the currently running function in JavaScript?我可以在 JavaScript 中获取当前正在运行的函数的名称吗?
【发布时间】:2010-11-04 00:52:07
【问题描述】:

是否可以这样做:

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

我的堆栈中有 Dojo 和 jQuery 框架,所以如果其中任何一个更容易,它们都是可用的。

【问题讨论】:

标签: javascript jquery dojo-1.6


【解决方案1】:

arguments 对象是所有非箭头函数中可用的局部变量。
您可以通过使用 arguments 对象在该函数中引用该函数的参数。
它对调用函数时使用的每个参数都有条目,第一个条目的索引为 0。

所以你基本上可以使用arguments.callee.name,但在这样的命名函数中:

function i_have_a_name() {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
My name is: i_have_a_name

不幸的是,它在箭头函数中不可用:

const i_have_a_name = () => {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
Uncaught ReferenceError: arguments is not defined
    at i_have_a_name (REPL3:2:32)

来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

【讨论】:

    【解决方案2】:

    由于 arguments.callee.name 是非标准的,并且在 ECMAScript 5 严格模式 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee) 中被禁止,动态检索函数名称 [如魔术变量] 的简单解决方案是使用作用域变量,并且 Function .name 属性。

    {
      function foo() {
        alert (a.name);
      }; let a = foo
    }
    {
      function foo2() {
        alert(a.name)
      }; let a = foo2
    };
    foo();//logs foo
    foo2();//logs foo2
    

    注意:嵌套函数不再是源元素,因此不会被提升。此外,此技术不适用于匿名函数。

    【讨论】:

      【解决方案3】:

      在 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 - get current function name

      【讨论】:

      • 其实,其实更关注你的问题,听起来你可能想要额外的垃圾:)
      • 在 ES5 严格模式下中断。
      • 哦...这就是为什么人们总是在回复速度上击败我。我没想到。
      • 如果你为你的方法使用了一个对象字面量并且没有实际的方法名,那么这将不能作为参数工作。被调用者就像一个匿名函数,它不会携带任何函数名。您必须确保将该函数名称添加两次。看看这个 jsfiddle 示例:jsfiddle.net/ncays。不过,另一个问题是 arguments.callee 在严格模式下是不允许的。
      • 您可以在某些环境中使用argument.callee.name。适用于 Chrome。
      【解决方案4】:

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

      现在,我不是一个了解所有浏览器历史的专业网络开发人员,以下是我在 2019 年 chrome 浏览器中的工作方式:

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

      其他一些答案遇到了一些关于严格的 javascript 代码和诸如此类的 chrome 错误。

      【讨论】:

      • this 的重复答案(比您的答案早 3 年)。
      【解决方案5】:

      这是Igor Ostroumov's 答案的变体:

      如果您想将其用作参数的默认值,则需要考虑对 '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();
      }
      

      【讨论】:

        【解决方案6】:

        下面sn-p中的getMyName函数返回调用函数的名字。这是一个 hack,依赖于 non-standard 功能: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 is not allowed in strict modeFunction.prototype.calleris non-standard and not allowed in strict mode

        【讨论】:

        • 将此扩展为还显示函数中的位置并支持匿名函数: .replace(/^\s+at\s(.+?)(?:\s.*:|:)( .*?):(.*?))?$/g, '$1 ($2:$3)' )
        • Function.prototype.caller 在严格模式下也是不允许的。
        • 即使是箭头函数也能完美运行,被低估的答案
        【解决方案7】:
        (function f() {
            console.log(f.name);  //logs f
        })();
        

        打字稿变体:

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

        注意仅在 ES6/ES2015 兼容引擎中可用。 For more see

        【讨论】:

        【解决方案8】:

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

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

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

        function foo() { 
          console.log(getFuncName())
        }
        
        foo() 
        // Logs: "foo"
        

        【讨论】:

        • 谢谢,这比解析字符串要优雅得多。
        • 这似乎是最好的答案!
        • 完美。那时 JS 没有原生常量,就像 PHP 有 Magic 常量一样......
        • Chrome 给我一个类型错误,因为调用者上不存在属性“名称”。然而,检查显示这有效:function getFuncName() { return getFuncName.name }
        • @TomAnderson 进行更改后,您现在将获得 getFuncName 的名称,而不是其调用者的名称。
        【解决方案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 时才有效

        【讨论】:

        • 这是我使用的答案。本质上,它是一种单线解决方案。
        【解决方案10】:

        信息以 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
        

        【讨论】:

          【解决方案11】:

          这是一个单行:

              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.');
              }
          

          【讨论】:

            【解决方案12】:

            根据MDN

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

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

            【讨论】:

              【解决方案13】:

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

              【讨论】:

              • "nom" 是法语中的 "name"。这种细节是否会在浏览器的语言版本之间发生变化?我不这么认为。
              【解决方案14】:

              可以在此答案中找到对此的更新答案: https://stackoverflow.com/a/2161470/632495

              如果您不想点击:

              function test() {
                var z = arguments.callee.name;
                console.log(z);
              }
              

              【讨论】:

                【解决方案15】:

                我在这里看到的几个回复的组合。 (在 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 Fiddle 演示:http://jsfiddle.net/mjgqfhbe/

                【讨论】:

                  【解决方案16】:

                  这必须归入“世界上最丑陋的黑客”类别,但给你。

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

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

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

                  【讨论】:

                  • 很酷的解决方案,但仅供参考 Function#caller 是非标准的 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
                  • 如果该函数是从数据库中动态创建的,并且需要与函数名称相关的函数内部的上下文信息,那么了解当前函数的名称可能是必不可少的。
                  【解决方案17】:

                  应该这样做:

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

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

                  【讨论】:

                  • 这对我有用,但我认为您的正则表达式中有错字。我必须在[ 之前去掉反斜杠
                  • @declan:是的,你是对的。令人惊讶的是,在将近 3 年的时间里,没有其他人指出这个答案一直在这里 :-)
                  • @AndyE 可能没有人指出,因为一旦我们看到一个正则表达式,我们就会进入 TL;DR 模式并寻找其他答案;)
                  【解决方案18】:

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

                  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()可选回调,或在超时/间隔回调中,(即您只传递一个函数名称)。

                  【讨论】:

                    【解决方案19】:

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

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

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

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

                    【讨论】:

                    • 我正在处理一个错误处理程序,我想报告调用函数。
                    【解决方案20】:

                    对于非匿名函数

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

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

                    【讨论】:

                    • 在 Chrome 中效果很好。比公认的答案好得多。
                    • 值得牢记:eslint.org/docs/rules/no-caller > “在 JavaScript 的未来版本中已弃用,并且在 ECMAScript 5 严格模式下禁止使用它们。”
                    【解决方案21】:

                    试试:

                    alert(arguments.callee.toString());
                    

                    【讨论】:

                    • 这会将整个函数作为字符串返回
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-04-15
                    • 1970-01-01
                    • 2011-09-29
                    • 1970-01-01
                    • 2012-01-12
                    相关资源
                    最近更新 更多