Чи можу я отримати ім'я поточно запущеної функції в JavaScript?


184

Чи можна це зробити:

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

У мене в структурі є рамки Dojo та jQuery, тому якщо будь-який із них полегшує їх, вони доступні.

Відповіді:


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 - отримання поточної назви функції .


Насправді, фактично приділяючи більше уваги своєму питанню, це здається, що ви могли б захотіти зайвих мотлохів :)
Метт,

23
@Andrew - Ти маєш рацію, я мав це сказати. Це була швидка копія / вставка / очищення чогось, про що я вже робив закладки, і контроль з мого боку. Дякую, що додали його до моєї публікації.
Метт

81
Порушує в жорсткому режимі ES5.
Райнос

4
Ох, тому люди завжди били мене на швидкість відповіді. Я не думав про це.
Ерік Реппен

9
якщо ви використовуєте об'єкт-літерал для своїх методів і не маєте власного імені методу, це не буде працювати, оскільки аргументи.callee діють як анонімна функція, яка не буде мати жодної назви функції. Вам слід переконатися, що ви додали це ім'я двічі. Погляньте на цей приклад jsfiddle : jsfiddle.net/ncays . Інша проблема з цим, однак, полягає в тому, що arguments.calleeце заборонено в суворій режимі.
Геллатан

75

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

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

Але у випадку обробника помилок результатом було б назву функції обробника помилок, чи не так?


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 з магічними константами ...
stamster

Chrome видає мені помилку типу, оскільки властивість "ім'я" не існує на абонента. Однак перевірка виявила, що це спрацювало:function getFuncName() { return getFuncName.name }
Том Андерсон,

@TomAnderson зі своєю зміною тепер ви отримуєте ім'я, getFuncNameа не ім’я його абонента.
Марк Маккенна

30

За даними MDN

Попередження: 5-е видання ECMAScript (ES5) забороняє використовувати argument.callee () в суворому режимі. Уникайте використання argument.callee (), або даючи ім'я виразам функції, або використовуйте декларацію функції, де функція повинна викликати себе.

Як зазначалося, це стосується лише, якщо ваш сценарій використовує "суворий режим". Це в основному з міркувань безпеки, і, на жаль, на даний момент альтернативи цьому немає.


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/…
Max Heiber

Знання імені поточної функції може бути важливим, якщо ця функція створюється динамічно з бази даних та потребує контекстної інформації всередині функції, яка введена до імені функції.
Пол Черноч

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 / функцій


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. *: |:) (. *?): (. * ?))? $ / 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 (), або у зворотному режимі викликів / інтервалів (тобто ви передаєте лише NAME).


2

Назва поточної функції та те, як її можна отримати, схоже, змінилися за останні 10 років, оскільки це питання було задано.

Тепер, не будучи професійним веб-розробником, який знає про всі історії всіх браузерів, які коли-небудь існували, ось як це працює для мене в хромованому браузері 2019 року:

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
Я працюю над обробкою помилок і хочу повідомити про функцію виклику.
скругман

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/



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

Це варіант Ігоря Остроумова :

Якщо ви хочете використовувати його як значення за замовчуванням для параметра, вам потрібно врахувати виклик другого рівня для "абонента":

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" - це "ім'я" французькою мовою. Чи змінюється така деталізація між мовними версіями браузерів? Я б не вважав цього.
argyle
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.