Как получить имя функции из этой функции? - PullRequest
229 голосов
/ 15 апреля 2010

Как я могу получить доступ к имени функции внутри этой функции?

// parasitic inheritance
var ns.parent.child = function() {
  var parent = new ns.parent();
  parent.newFunc = function() {

  }
  return parent;
}

var ns.parent = function() {
  // at this point, i want to know who the child is that called the parent
  // ie
}

var obj = new ns.parent.child();

Ответы [ 20 ]

151 голосов
/ 30 марта 2013

В ES5 лучшее, что нужно сделать, это:

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

Использование Function.caller не является стандартным. Function.caller и arguments.callee запрещены в строгом режиме.

Редактировать: нижеприведенный ответ nus на основе регулярных выражений достигает того же, но имеет лучшую производительность!

В ES6 вы можете просто использовать myFunction.name.

Примечание. Помните, что некоторые минификаторы JS могут выбрасывать имена функций для лучшего сжатия; вам может потребоваться изменить их настройки, чтобы избежать этого.

121 голосов
/ 29 июля 2013

ES6 (на основе ответа Сэнди Халима ниже):

myFunction.name

Объяснение по MDN .По состоянию на 2015 год работает в nodejs и во всех основных браузерах, кроме IE.

Примечание: для связанных функций это даст "bound <originalName>".Вам придется лишить «связанного», если вы хотите получить оригинальное имя.


ES5 (вдохновленный ответом Влада):

Если у вас естьссылку на функцию вы можете сделать:

function functionName( func )
{
    // Match:
    // - ^          the beginning of the string
    // - function   the word 'function'
    // - \s+        at least some white space
    // - ([\w\$]+)  capture one or more valid JavaScript identifier characters
    // - \s*        optionally followed by white space (in theory there won't be any here,
    //              so if performance is an issue this can be omitted[1]
    // - \(         followed by an opening brace
    //
    var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )

    return  result  ?  result[ 1 ]  :  '' // for an anonymous function there won't be a match
}
  • Я не запускал модульные тесты по этому вопросу или проверял различия в реализации, но в принципе это должно работать, если не оставить комментарий.
  • Примечание: не будет работать с привязанными функциями
  • Примечание: caller и callee считаются устаревшими.

[1] Я включил его сюда, потому что он является законным и достаточно часто инструменты подсветки синтаксиса не учитывают пробел между именем функции и круглыми скобками.С другой стороны, мне неизвестно о какой-либо реализации .toString (), которая будет включать здесь пробелы, поэтому вы можете ее опустить.


В качестве ответа наИсходный вопрос, я бы отказался от паразитического наследования и пошел бы к более традиционным шаблонам проектирования ООП.Я написал TidBits.OoJs для удобного написания кода ООП на JavaScript с набором функций, имитирующим C ++ (пока не завершенным, но в основном).

Я вижу из комментариев, что вы хотели быизбегайте передачи информации, необходимой parent его конструктору.Я должен признать, что традиционные шаблоны проектирования не спасут вас от этого, хотя, как правило, считается хорошей идеей сделать ваши зависимости очевидными и принудительными.

Я бы также предложил отказаться от анонимных функций.,Они только делают отладку и профилирование PITA, потому что все просто отображается как «анонимная функция», и я не вижу в них никакой пользы.

54 голосов
/ 04 апреля 2011

что вы делаете, это присваиваете неназванную функцию переменной. вам, вероятно, нужно вместо выражения именованной функции (http://kangax.github.com/nfe/).

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

однако я не уверен, сколько это кросс-браузер; В IE6 есть проблема, из-за которой имя функции просачивается во внешнюю область. Кроме того, arguments.callee является устаревшим и приведет к ошибке, если вы используете strict mode.

17 голосов
/ 10 августа 2015

Любой constructor предоставляет свойство name, которое является именем функции. Вы получаете доступ к constructor через экземпляр (используя new) или prototype:

function Person() {
  console.log(this.constructor.name); //Person
}

var p = new Person();
console.log(p.constructor.name); //Person

console.log(Person.prototype.constructor.name);  //Person
14 голосов
/ 03 апреля 2011

Это может работать для вас:

function foo() { bar(); }

function bar() { console.log(bar.caller.name); }

при запуске foo () будет выведено «foo» или не определено, если вы вызываете из анонимной функции.

Он также работает с конструкторами, в этом случае он будет выводить имя вызывающего конструктора (например, "Foo").

Подробнее здесь: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

Они утверждают, что он нестандартный, но также поддерживается всеми основными браузерами: Firefox, Safari, Chrome, Opera и IE.

8 голосов
/ 15 апреля 2010

Вы не можете.Функции не имеют имен в соответствии со стандартом (хотя у mozilla есть такой атрибут) - их можно назначать только переменным с именами.

Также ваш комментарий:

// access fully qualified name (ie "my.namespace.myFunc")

находится внутри функции my.namespace.myFunc.getFn

Что вы можете сделать, это вернуть конструктор объекта, созданного новым

Так что вы могли бы сказать

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
7 голосов
/ 14 декабря 2017

Похоже, самая глупая вещь, которую я написал в своей жизни, но это смешно: D

function getName(d){
  const error = new Error();
  const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=@)/) || [])[0];
  const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
  const safariMatch = error.stack.split('\n')[0 + d];

  // firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
  // chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
  // safariMatch ? console.log('safariMatch', safariMatch) : void 0;

  return firefoxMatch || chromeMatch || safariMatch;
}

d - глубина стека. 0 - вернуть имя этой функции, 1 - родитель и т. Д .;
[0 + d] - просто для понимания - что происходит;
firefoxMatch - работает для сафари, но у меня было очень мало времени на тестирование, потому что владелец мака вернулся после курения и отогнал меня: '(

Тестирование:

function limbo(){
  for(let i = 0; i < 4; i++){
    console.log(getName(i));
  }
}
function lust(){
  limbo();
}
function gluttony(){
  lust();
}

gluttony();

Результат:
Chrome:
enter image description here

Fitefox:
enter image description here

Это решение создавалось только просто для удовольствия ! Не используйте его для реальных проектов. Это не зависит от спецификации ES, это зависит только от реализации браузера. После следующего обновления chrome / firefox / safari оно может быть повреждено.
Более того, при обработке ошибок (га) нет - если d будет больше длины стека - вы получите ошибку;
Для других шаблонов сообщений об ошибках wrowsers - вы получите ошибку;
Он должен работать для классов ES6 (.split('.').pop()), но вы можете получить erorr;

4 голосов
/ 10 октября 2014

Вы можете использовать name свойство для получения имени функции, если вы не используете анонимную функцию

Например:

var Person = function Person () {
  this.someMethod = function () {};
};

Person.prototype.getSomeMethodName = function () {
  return this.someMethod.name;
};

var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());

Теперь давайте попробуем с именованной функцией

var Person = function Person () {
  this.someMethod = function someMethod() {};
};

теперь вы можете использовать

// will return "someMethod"
p.getSomeMethodName()
3 голосов
/ 20 июня 2013

Вы можете использовать Function.name:

В большинстве реализаций JavaScript, когда у вас есть ссылка на конструктор в области видимости, вы можете получить его строковое имя из свойства name (например, Function.name или Object.constructor.name

Вы можете использовать Function.callee:

Собственный метод arguments.caller устарел, но большинство браузеров поддерживают Function.caller, который будет возвращать фактический вызывающий объект (его тело кода): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller

Вы можете создать исходную карту :

Если вам нужна буквальная сигнатура функции (ее «имя»), а не сам объект, вам, возможно, придется прибегнуть к чему-то более настраиваемому, например, создать ссылку на массив значений строки API, которые вы Вам нужно будет часто получать доступ. Вы можете отобразить их вместе, используя Object.keys() и ваш массив строк, или заглянуть в библиотеку исходных карт Mozilla на GitHub для более крупных проектов: https://github.com/mozilla/source-map

3 голосов
/ 13 декабря 2014

Вы можете использовать это, но это не для всех браузеров, только для тех, которые поддерживают Error.stack

function VamosRafa(){ 
  var a = new Error().stack.match(/at (.*?) /);
  console.log(a[1]);
} 
VamosRafa();

Конечно, это для текущей функции, но вы поняли.

ура!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...