Как получить имя функции из этой функции?

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

// 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();

Ответ 1

В 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 regex ниже обеспечивает одно и то же, но имеет лучшую производительность!

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

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

Ответ 2

ES6 (вдохновлен ответом sendy halim ниже):

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, чтобы удобно писать код OOP в JavaScript с набором функций, имитирующим С++ (еще не полный, но в основном).

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

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

Ответ 3

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

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

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

Ответ 4

Любой 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

Ответ 5

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

function foo() { bar(); }

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

running foo() выведет "foo" или undefined, если вы вызываете анонимную функцию.

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

Дополнительная информация здесь: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

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

Ответ 6

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

function getName(d){
  const error = new Error();
  const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*([email protected])/) || [])[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 - работает для сафари, но у меня было очень мало времени на тестирование, потому что владелец Mac вернулся после курения и отогнал меня: '(

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

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

gluttony();

Результат:
Хром:
enter image description here

Fitefox:
enter image description here

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

Ответ 7

Вы не можете. Функции не имеют имен в соответствии со стандартом (хотя у 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

Ответ 8

Вы можете использовать свойство 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()

Ответ 9

Вы можете использовать имя конструктора как:

{your_function}.prototype.constructor.name

этот код просто возвращает имя метода.

Ответ 10

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

В большинстве реализаций JavaScript, когда у вас есть ссылка на конструктор в области видимости, вы можете получить его имя строки из своего свойства имени (например, имя_функции или 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

Ответ 11

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

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

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

счастливый пускать слюни, пока вы код

Ответ 12

как часть ECMAScript 6 вы можете использовать Function.name method

function doSomething() {}

alert(doSomething.name); // alerts "doSomething"

Ответ 13

Я знаю, что это старый вопрос, но в последнее время я сталкивался с подобной проблемой, пытаясь украсить некоторые методы React Component для целей отладки. Как уже говорили люди, arguments.caller и arguments.callee запрещены в строгом режиме, который, вероятно, включен по умолчанию в вашем переводе React. Вы можете либо отключить его, либо я смог придумать еще один хак, потому что в React все функции класса названы, вы можете это сделать:

Component.prototype.componentWillMount = function componentWillMount() {
    console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}

Ответ 14

У меня была аналогичная проблема, и я решил ее следующим образом:

Function.prototype.myname = function() {
   return this.toString()
       .substr( 0, this.toString().indexOf( "(" ) )
       .replace( "function ", "" ); 
}

Этот код более удобным образом реализует один ответ, который я уже читал здесь в начале этой дискуссии. Теперь у меня есть функция-член, получающая имя любого объекта функции. Здесь полный script...

<script language="javascript" TYPE="text/javascript">

    Function.prototype.myname = function() { 
        return this.toString()
            .substr( 0, this.toString().indexOf( "(" ) )
            .replace("function ", "" ); 
    }
    function call_this( _fn ) { document.write( _fn.myname() ); }
    function _yeaaahhh() { /* do something */ }
    call_this( _yeaaahhh ); 

</script>

Ответ 15

Это сработало для меня.

function AbstractDomainClass() {
    this.className = function() {
        if (!this.$className) {
            var className = this.constructor.toString();
            className = className.substr('function '.length);
            className = className.substr(0, className.indexOf('('));
            this.$className = className;
        }
        return this.$className;
    }
}

Тестовый код:

var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');

Ответ 16

Если я понял, что вы хотите сделать, это то, что я делаю внутри конструктора функции.

if (!(this instanceof arguments.callee)) {
    throw "ReferenceError: " + arguments.callee.name + " is not defined";
}

Ответ 17

Это будет работать в ES5, ES6, во всех браузерах и в строгом режиме.

Вот как это выглядит с именованной функцией.

(function myName() {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)

Вот как это выглядит с анонимной функцией.

(() => {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15

Ответ 19

вы можете использовать Error.stack для отслеживания имени функции и точной позиции, в которой вы находитесь.

См. stacktrace.js

Ответ 20

Легкий способ получить имя функции изнутри функции fuction.

function x(){alert(this.name)};x()