it-swarm.com.de

Wie erhalte ich den Funktionsnamen in dieser Funktion?

Wie kann ich von dieser Funktion aus auf einen Funktionsnamen zugreifen?

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

In ES5 ist das Beste, was Sie tun können:

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

Mit Function.caller ist nicht standard. Function.caller und arguments.callee sind beide im strikten Modus verboten.

Edit: Nus 'Regex-basierte Antwort unten erreicht das gleiche, hat aber eine bessere Leistung!

In ES6 können Sie einfach myFunction.name.

Hinweis: Beachten Sie, dass einige JS-Minifier möglicherweise Funktionsnamen wegwerfen, um eine bessere Komprimierung zu erzielen. Möglicherweise müssen Sie die Einstellungen anpassen, um dies zu vermeiden.

154
Vlad A Ionescu

ES6 (inspiriert von sendy halims Antwort unten):

myFunction.name

Erklärung zu MDN . Ab 2015 funktioniert in NodeJS und allen gängigen Browsern außer IE.

Hinweis: Bei gebundenen Funktionen erhalten Sie "bound <originalName>". Sie müssen die "Grenze" entfernen, wenn Sie den ursprünglichen Namen erhalten möchten.


ES5 (inspiriert von Vlads Antwort):

Wenn Sie einen Verweis auf die Funktion haben, können Sie Folgendes tun:

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
}
  • Ich habe keine Unit-Tests durchgeführt oder Implementierungsunterschiede überprüft, aber im Prinzip sollte es funktionieren, wenn ich keinen Kommentar hinterlasse.
  • Hinweis: Funktioniert nicht mit gebundenen Funktionen
  • Hinweis: caller und callee gelten als veraltet.

[1] Ich füge es hier hinzu, weil es legal ist und oft genug Syntax-Hervorhebungswerkzeuge den Leerraum zwischen Funktionsnamen nicht berücksichtigen und Klammern. Andererseits sind mir keine Implementierungen von .toString () bekannt, die hier Leerzeichen enthalten. Deshalb können Sie sie weglassen.


Als Antwort auf die ursprüngliche Frage würde ich die parasitäre Vererbung fallen lassen und mich für einige traditionellere OOP Entwurfsmuster entscheiden. Ich habe ein TidBits.OoJs geschrieben, um bequem OOP - Code in JavaScript mit einem Feature-Set zu schreiben, das C++ imitiert (noch nicht vollständig, aber meistens).

Aus den Kommentaren geht hervor, dass Sie vermeiden möchten, dass Informationen, die parent benötigt, an den Konstruktor übergeben werden. Ich muss zugeben, dass traditionelle Entwurfsmuster Sie nicht davon abhalten, da es im Allgemeinen als eine gute Sache angesehen wird, Ihre Abhängigkeiten offensichtlich zu machen und durchzusetzen.

Ich würde auch vorschlagen, anonyme Funktionen zu meiden. Sie machen das Debuggen und Profilieren nur zu einer PITA, weil alles nur als "anonyme Funktion" angezeigt wird, und es gibt keinen Vorteil für sie, den ich kenne.

124
user1115652

sie weisen einer Variablen eine unbenannte Funktion zu. Möglicherweise benötigen Sie stattdessen den Ausdruck "named function" ( http://kangax.github.com/nfe/ ).

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

ich bin mir jedoch nicht sicher, wie viel Cross-Browser das ist. Es gibt ein Problem mit IE6, durch das der Name der Funktion in den äußeren Bereich gelangt. Außerdem ist arguments.callee veraltet und führt zu Fehlern, wenn Sie strict mode verwenden.

54
wildcard

Jedes constructor macht eine Eigenschaft name verfügbar, bei der es sich um den Funktionsnamen handelt. Sie greifen über eine Instanz (mit constructor) oder über ein new auf prototype zu:

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
17
roland

Das könnte für Sie funktionieren:

function foo() { bar(); }

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

wenn Sie foo () ausführen, wird "foo" oder "undefined" ausgegeben, wenn Sie eine anonyme Funktion aufrufen.

Es funktioniert auch mit Konstruktoren. In diesem Fall wird der Name des aufrufenden Konstruktors ausgegeben (z. B. "Foo").

Weitere Informationen finden Sie hier: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

Sie behaupten, es sei nicht Standard, aber es wird von allen gängigen Browsern unterstützt: Firefox, Safari, Chrome, Opera und IE.

14
Jacob Mouka

Es sieht aus wie das dümmste, was ich in meinem Leben geschrieben habe, aber es ist lustig: 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 - Tiefe des Stapels. 0 - diesen Funktionsnamen zurückgeben, 1 - übergeordnetes Element usw .;
[0 + d] - nur zum Verständnis - was passiert;
firefoxMatch - funktioniert für Safari, aber ich hatte wirklich ein wenig Zeit zum Testen, weil Macs Besitzer nach dem Rauchen zurückgekehrt war und mich weggefahren hat: '(

Testen:

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

gluttony();

Ergebnis:
Chrome:
enter image description here

Fitefox:
enter image description here

Diese Lösung wurde nur erstellt nur zum Spaß! Verwenden Sie es nicht für echte Projekte. Dies hängt nicht von der ES-Spezifikation ab, sondern nur von der Browser-Realisierung. Nach dem nächsten Chrome/Firefox/Safari-Update ist es möglicherweise defekt.
Darüber hinaus gibt es keine Fehler (ha) -Verarbeitung - wenn d größer als die Stapellänge ist, erhalten Sie einen Fehler.
Für das Messaging-Muster eines anderen Wrower-Fehlers wird ein Fehler angezeigt.
Es muss für ES6-Klassen (.split('.').pop()) funktionieren, aber Sie können trotzdem einen Fehler bekommen.

9
user3335966

Das kannst du nicht. Funktionen haben laut Standard keine Namen (obwohl Mozilla ein solches Attribut hat) - sie können nur Variablen mit Namen zugewiesen werden.

Auch dein Kommentar:

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

befindet sich in der Funktion my.namespace.myFunc.getFn

Sie können den Konstruktor eines von new erstellten Objekts zurückgeben

So könnte man sagen

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
8
plodder

Sie können die Eigenschaft name verwenden, um den Funktionsnamen abzurufen, es sei denn, Sie verwenden eine anonyme Funktion

Zum Beispiel:

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

versuchen wir es jetzt mit der benannten Funktion

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

jetzt können Sie verwenden

// will return "someMethod"
p.getSomeMethodName()
4
sendy halim

Sie können Function.name verwenden:

In den meisten Implementierungen von JavaScript können Sie den Namen der Zeichenfolge aus der Eigenschaft name abrufen, sobald Sie die Referenz Ihres Konstruktors im Gültigkeitsbereich haben (z. B. Function.name oder Object.constructor.name)

Sie können Function.callee verwenden:

Die native arguments.caller - Methode ist veraltet, aber die meisten Browser unterstützen Function.caller, Wodurch das tatsächlich aufrufende Objekt (sein Code) zurückgegeben wird: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller? redirectlocale = de-DE & redirectslug = JavaScript% 2FReference% 2FGlobal_Objects% 2FFunction% 2Fcaller

Sie können eine Quell-Map erstellen :

Wenn Sie nur die Literalfunktionssignatur (den "Namen" davon) und nicht das Objekt selbst benötigen, müssen Sie möglicherweise auf etwas Anpassbares zurückgreifen, z. B. das Erstellen einer Arrayreferenz der API-Zeichenfolgenwerte, die Sie benötigen häufig zugreifen. Sie können sie zusammen mit Object.keys() und Ihrem String-Array zuordnen oder in Mozillas Source-Maps-Bibliothek auf GitHub nachsehen, um größere Projekte zu erstellen: https: // github. com/mozilla/source-map

3
Benny

als Teil von ECMAScript 6 Sie können die Methode Funktionsname verwenden

function doSomething() {}

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

Sie können Konstruktornamen wie folgt verwenden:

{your_function}.prototype.constructor.name

dieser Code gibt einfach den Namen einer Methode zurück.

3

Sie können dies verwenden, es ist jedoch nicht für alle Browser geeignet, sondern nur für diejenigen, die Error.stack unterstützen

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

Natürlich ist dies für die aktuelle Funktion, aber Sie bekommen die Idee.

Prost!

3
no_ripcord

Ich weiß, dass dies eine alte Frage ist, aber in letzter Zeit habe ich ein ähnliches Problem festgestellt, als ich versucht habe, die Methoden von React Component für Debugging-Zwecke zu dekorieren. Wie bereits erwähnt, sind arguments.caller Und arguments.callee Im strikten Modus verboten. Dies ist wahrscheinlich standardmäßig in Ihrem React Transpiling aktiviert. Sie können es entweder deaktivieren oder ich konnte mir einen anderen Hack einfallen lassen, da in React alle Klassenfunktionen benannt sind. Sie können dies tatsächlich tun:

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

Das hat bei mir funktioniert.

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;
    }
}

Testcode:

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

Ich hatte ein ähnliches Problem und habe es folgendermaßen gelöst:

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

Dieser Code implementiert auf eine bequemere Art und Weise eine Antwort, die ich oben in dieser Diskussion bereits gelesen habe. Jetzt habe ich eine Mitgliedsfunktion, die den Namen eines Funktionsobjekts abruft. Hier ist das vollständige Skript ...

<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>
1
Sandro Rosa

Wenn ich verstanden habe, was Sie tun wollten, ist dies das, was ich in einem Funktionskonstruktor tue.

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

Dies funktioniert in ES5, ES6, allen Browsern und Funktionen im strengen Modus.

So sieht es mit einer benannten Funktion aus.

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

So sieht es mit einer anonymen Funktion aus.

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