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

185

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

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

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

sprugman
источник

Ответы:

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
источник
На самом деле, на самом деле обращают больше внимания на ваш вопрос, это звучит , как вы могли бы хотеть дополнительный мусор :)
Matt
23
@ Андрей - Вы правы, я должен был это заявить. Это было быстрое копирование / вставка / очистка того, что я уже добавил в закладки, и упущение с моей стороны. Спасибо за добавление его в мой пост.
Мэтт
81
Перерывы в строгом режиме ES5.
Райнос
4
Ох ... вот почему люди всегда бьют меня по скорости, чтобы ответить. Я не думал об этом.
Эрик Реппен
9
если вы используете литерал объекта для своих методов и не используете фактическое имя метода, то это не будет работать как arguments.callee действует как анонимная функция, которая не будет содержать никакого имени функции. Вы должны убедиться, что вы добавили это имя функции дважды. Взгляните на этот пример jsfiddle : jsfiddle.net/ncays . другая проблема с этим, однако, состоит в том, что arguments.calleeэто не разрешено в строгом режиме.
Hellatan
75

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

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

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

fforw
источник
2
Прекрасно работает в Chrome. Гораздо лучше, чем принятый ответ.
B Семь
1
Стоит помнить: eslint.org/docs/rules/no-caller > «не рекомендуется в будущих версиях JavaScript, и их использование запрещено в ECMAScript 5 в строгом режиме».
Джереми
44

Все, что вам нужно, просто. Создать функцию:

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

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

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

foo() 
// Logs: "foo"
Игорь Остроумов
источник
3
Спасибо, это намного элегантнее, чем анализ строки.
modle13
1
Кажется, это лучший ответ!
Сергей
Отлично. Именно тогда у JS нет нативных констант, как у PHP с константами Magic ...
stamster
Chrome выдаёт мне ошибку типа, потому что свойство 'name' не существует в вызывающей программе. Однако проверка показала, что это сработало:function getFuncName() { return getFuncName.name }
Том Андерсон
@TomAnderson с вашим изменением, теперь вы получаете имя, getFuncNameа не имя вызывающего абонента.
Марк МакКенна
30

По данным МДН

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

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

Laimis
источник
21

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

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

Для звонящего просто используйте caller.toString().

Энди Э
источник
8
Это сработало для меня, но я думаю, что в вашем регулярном выражении есть опечатка. Мне пришлось снять обратную косую черту до[
деклана
4
@declan: да, вы правы. Удивительно, что никто другой не указал, что за почти 3 года этот ответ был здесь :-)
Энди Э,
@AndyE, вероятно, никто не указал на это, потому что как только мы видим регулярное выражение, мы входим в режим TL; DR и ищем другие ответы;)
BitTickler
11

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

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

Однако выяснение имени вызывающей функции может быть довольно полезным для функции трассировки. Это с регулярным выражением, но использование 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();
Джеймс Хугард
источник
классное решение, но вызывающая функция FYI # является нестандартной developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Макс Хайбер
Знание имени текущей функции может быть важным, если эта функция создается динамически из базы данных и нуждается в контекстной информации внутри функции, которая связана с именем функции.
Павел Чернох
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Функция во фрагменте ниже возвращает имя вызывающей функции. Это хак и полагается на нестандартной функции: 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. *: |:) (. *?): (. * ?))? $ / г, '$ 1 ($ 2: $ 3)')
кофифус
Function.prototype.caller также не разрешен в строгом режиме.
18:18
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 (), или в обратном вызове тайм-аутов / интервалов (т.е. вы передаете только имя функции).

Sampiolin
источник
2

Название текущей функции и то, как ее можно получить, изменилось за последние 10 лет, так как этот вопрос был задан.

Теперь, не будучи профессиональным веб-разработчиком, который знает обо всех историях всех браузеров, когда-либо существовавших, вот как это работает для меня в браузере Chrome 2019 года:

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

Некоторые из других ответов натолкнулись на некоторые хромированные ошибки о строгом коде JavaScript и еще много чего.

BitTickler
источник
1

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

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

Вот функция, которая выдаст свое собственное имя:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}
Эндрю Хэйр
источник
5
Я работаю над обработчиком ошибок и хочу сообщить о вызывающей функции.
spruman
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 Fiddle: http://jsfiddle.net/mjgqfhbe/

buddamus
источник
1

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

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

function test() {
  var z = arguments.callee.name;
  console.log(z);
}
Jon49
источник
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
PADYMKO
источник
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. Для более см.

Ole
источник
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.');
    }
VRMBW
источник
0

Это вариант Игоря Остроумова ответа :

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

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();
}
SMAG
источник
-1

Пытаться:

alert(arguments.callee.toString());
Дениз Доган
источник
3
Это вернет всю функцию в виде строки
Энди E
-7

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

Бэзил
источник
12
«nom» - это «имя» по-французски. Меняется ли такая детализация между языковыми версиями браузеров? Я бы так не думал.
Аргайл