Могу ли я получить имя текущей функции в JavaScript?

возможно ли это сделать:

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

У меня есть фреймворки Dojo и jQuery в моем стеке, поэтому, если любой из них облегчает работу, они доступны.

17 ответов


вы должны быть в состоянии сделать это с помощью 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-получить текущее имя функции.


для неанонимных функций

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

но в случае обработчика ошибок результатом будет имя функции обработчика ошибок, не так ли?


Это должно сделать это:

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

для вызывающего абонента просто используйте caller.toString().


по данным MDN

предупреждение: 5-е издание ECMAScript (ES5) запрещает использование аргументов.callee () в строгом режиме. Избегайте использования аргументов.callee (), либо давая выражениям функции имя, либо используя объявление функции, где функция должна вызывать себя.

Как уже отмечалось, это относится только если ваш скрипт использует "строгий режим". Это в основном по соображениям безопасности, и, к сожалению, в настоящее время нет Альтернатива для этого.


Это должно пойти в категорию "самых уродливых хаков в мире", но здесь вы идете.

во-первых, печать имени настоящее функция (как и в других ответах), кажется, имеет ограниченное использование для меня, так как вы уже знаете, что такое функция!

однако, узнав имя вызов функция может быть очень полезной для функции трассировки. Это с regexp, но использование indexOf будет около 3x быстрее:

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 getFuncName() {
   return getFuncName.caller.name
}

после этого, когда вам нужно, вы просто использовать:

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

foo() 
// Logs: "foo"

вот способ, который будет работать:

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


другим вариантом использования может быть диспетчер событий, связанный во время выполнения:

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() необязательный обратный вызов или в таймаутах / интервалах обратных вызовов (т. е. вы передаете только имя функции).


на getMyName функция в приведенном ниже фрагменте возвращает имя вызывающей функции. Это хак и полагается на нестандартное характеристика: 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, '' );
                return stack
}

function foo(){
  return getMyName()
}

function bar() {
  return foo()
}

console.log(bar())

о других решениях:arguments.callee не работает в строгом режиме и Function.prototype.caller is нестандартное, но имеет лучшую поддержку, чем Error.prototype.stack.


так как вы написали функцию с именем foo и вы знаете, что это в myfile.js почему вам нужно получить эту информацию динамически?

это, как говорится, вы можете использовать arguments.callee.toString() внутри функции (это строковое представление всей функции) и регулярное выражение значения имени функции.

вот функция, которая выплюнет свое собственное имя:

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

обновленный ответ на этот вопрос можно найти в этом ответе: https://stackoverflow.com/a/2161470/632495

и, если вам не хочется нажимать:

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

сочетание нескольких ответов которые я видел здесь. (Протестировано в 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 Demo:http://jsfiddle.net/mjgqfhbe/


вот один лайнер:

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

информация актуальна на 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 и краю.


результаты для выражений функций

результат в NodeJS

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

в результате Хром

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

не работает в Firefox, Opera. Непроверенные на IE и краю.

Примечания:

  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

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

вариант машинописного текста:

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

f2(f1);  //Logs f1

Примечание доступно только в двигателях, совместимых с ES6/ES2015. подробнее


попробуй:

alert(arguments.callee.toString());

ответ короток: alert(arguments.callee.name);