Kann ich den Namen der aktuell ausgeführten Funktion in JavaScript abrufen?

182

Ist das möglich:

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

Ich habe die Dojo- und jQuery-Frameworks in meinem Stack. Wenn eines dieser Frameworks es einfacher macht, sind sie verfügbar.

Sprugman
quelle

Antworten:

196

In ES5 und höher gibt es keinen Zugriff auf diese Informationen.

In älteren Versionen von JS können Sie es mit verwenden arguments.callee.

Möglicherweise müssen Sie den Namen jedoch analysieren, da er wahrscheinlich zusätzlichen Müll enthält. In einigen Implementierungen können Sie den Namen jedoch einfach mit abrufen arguments.callee.name.

Parsing:

function DisplayMyName() 
{
   var myName = arguments.callee.toString();
   myName = myName.substr('function '.length);
   myName = myName.substr(0, myName.indexOf('('));

   alert(myName);
}

Quelle: Javascript - aktuellen Funktionsnamen abrufen .

Matt
quelle
Wenn Sie Ihrer Frage tatsächlich mehr Aufmerksamkeit schenken, klingt es so, als ob Sie den zusätzlichen Müll wollen :)
Matt
23
@ Andrew - Du hast recht, das hätte ich sagen sollen. Es war ein schnelles Kopieren / Einfügen / Bereinigen von etwas, das ich bereits mit einem Lesezeichen versehen hatte, und ein Versehen meinerseits. Vielen Dank, dass Sie es meinem Beitrag hinzugefügt haben.
Matt
80
Bricht im ES5-Strict-Modus ab.
Raynos
4
Oh ... deshalb haben mich die Leute immer geschlagen, wenn es darum ging, schnell zu antworten. Daran hatte ich nicht gedacht.
Erik Reppen
9
Wenn Sie für Ihre Methoden ein Objektliteral und keinen tatsächlichen Methodennamen verwenden, funktioniert dies nicht als Argument.callee verhält sich wie eine anonyme Funktion, die keinen Funktionsnamen trägt. Sie müssten sicherstellen, dass Sie diesen Funktionsnamen zweimal hinzufügen. Schauen Sie sich dieses jsfiddle-Beispiel an: jsfiddle.net/ncays . Ein weiteres Problem dabei ist jedoch, dass arguments.calleedies im strengen Modus nicht zulässig ist.
Hellatan
75

Für nicht anonyme Funktionen

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

Aber im Falle eines Fehlerbehandlers wäre das Ergebnis der Name der Fehlerbehandlungsfunktion, nicht wahr?

fforw
quelle
2
Funktioniert hervorragend in Chrome. Viel besser als akzeptierte Antwort.
B Seven
Beachten Sie Folgendes : eslint.org/docs/rules/no-caller > "In zukünftigen Versionen von JavaScript veraltet und deren Verwendung in ECMAScript 5 im strengen Modus verboten."
Jeremy
44

Alles was Sie brauchen ist einfach. Funktion erstellen:

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

Danach verwenden Sie, wann immer Sie möchten, einfach:

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

foo() 
// Logs: "foo"
Igor Ostroumov
quelle
3
Danke, das ist viel eleganter als das Parsen einer Zeichenfolge.
modle13
1
Es scheint die beste Antwort zu sein!
Sergey
Perfekt.
Dann hat
Chrome gibt mir einen Tippfehler, da die Eigenschaft 'Name' beim Aufrufer nicht vorhanden ist. Die Inspektion ergab jedoch, dass dies funktionierte:function getFuncName() { return getFuncName.name }
Tom Anderson
@ TomAnderson Mit Ihrer Änderung erhalten Sie jetzt den Namen getFuncNameund nicht den Namen des Anrufers.
Mark McKenna
30

Laut MDN

Warnung: Die 5. Ausgabe von ECMAScript (ES5) verbietet die Verwendung von Argumenten.callee () im strengen Modus. Vermeiden Sie die Verwendung von argument.callee (), indem Sie entweder Funktionsausdrücken einen Namen geben oder eine Funktionsdeklaration verwenden, bei der sich eine Funktion selbst aufrufen muss.

Wie bereits erwähnt, gilt dies nur, wenn Ihr Skript den "strengen Modus" verwendet. Dies ist hauptsächlich aus Sicherheitsgründen und leider gibt es derzeit keine Alternative dafür.

Laimis
quelle
21

Dies sollte es tun:

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

Verwenden Sie für den Anrufer einfach caller.toString().

Andy E.
quelle
8
Das hat bei mir funktioniert, aber ich denke, es gibt einen Tippfehler in Ihrem regulären Ausdruck. Ich musste den umgekehrten Schrägstrich herausnimmt , bevor die[
declan
4
@declan: Ja, du hast recht. Es ist überraschend, dass niemand sonst darauf hingewiesen hat, dass diese Antwort in den fast 3 Jahren hier war :-)
Andy E
@AndyE wahrscheinlich hat niemand darauf hingewiesen, denn sobald wir einen regulären Ausdruck sehen, wechseln wir in den TL; DR-Modus und suchen nach anderen Antworten;)
BitTickler
11

Dies muss in die Kategorie der "hässlichsten Hacks der Welt" gehen, aber los geht's.

Drucken Sie zuerst den Namen des aktuellen scheint mir das Funktion (wie in den anderen Antworten) nur eine begrenzte Verwendung zu haben, da Sie irgendwie bereits wissen, was die Funktion ist!

Das Herausfinden des Namens der aufrufenden Funktion kann jedoch für eine Ablaufverfolgungsfunktion sehr nützlich sein. Dies ist mit einem regulären Ausdruck, aber die Verwendung von indexOf wäre etwa dreimal schneller:

function getFunctionName() {
    var re = /function (.*?)\(/
    var s = getFunctionName.caller.toString();
    var m = re.exec( s )
    return m[1];
}

function me() {
    console.log( getFunctionName() );
}

me();
James Hugard
quelle
kühle Lösung, aber FYI Funktion # Anrufer sind nicht-Standard developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Max Heiber
Die Kenntnis des Namens der aktuellen Funktion kann von entscheidender Bedeutung sein, wenn diese Funktion dynamisch aus einer Datenbank erstellt wird und Kontextinformationen innerhalb der Funktion benötigt, die mit dem Funktionsnamen verknüpft sind.
Paul Chernoch
9

Hier ist ein Weg, der funktionieren wird:

export function getFunctionCallerName (){
  // gets the text between whitespace for second part of stacktrace
  return (new Error()).stack.match(/at (\S+)/g)[1].slice(3);
}

Dann in Ihren Tests:

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

});

Beachten Sie, dass der dritte Test nur funktioniert, wenn sich der Test in / util / functions befindet

Anthony
quelle
7

Die getMyNameFunktion im folgenden Snippet gibt den Namen der aufrufenden Funktion zurück. Es ist ein Hack und basiert auf nicht standardmäßigen Funktionen : Error.prototype.stack. Beachten Sie, dass das Format der von zurückgegebenen Zeichenfolge Error.prototype.stackin verschiedenen Engines unterschiedlich implementiert ist, sodass dies wahrscheinlich nicht überall funktioniert:

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

Über andere Lösungen: arguments.callee nicht im strikten Modus erlaubt und Function.prototype.callerist nicht-Standard und nicht im Strict - Modus erlaubt .

Max Heiber
quelle
Erweitern Sie dies, um auch die Position in der Funktion anzuzeigen und anonyme Funktionen zu unterstützen mit: .replace (/ ^ \ s + at \ s (. +?) (?: \ s. *: | :) (. *?): (. * ?))? $ / g, '$ 1 ($ 2: $ 3)')
Kofifus
Function.prototype.caller ist im strengen Modus ebenfalls nicht zulässig.
Fidschiaaron
1
Funktioniert perfekt auch für Pfeilfunktionen, unterschätzte Antwort
Hao Wu
3

Ein anderer Anwendungsfall könnte ein zur Laufzeit gebundener Ereignis-Dispatcher sein:

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

Der Vorteil hierbei ist, dass der Dispatcher leicht wiederverwendet werden kann und nicht die Dispatch-Warteschlange als Argument erhalten muss, sondern implizit den Aufrufnamen enthält ...

Am Ende wäre der hier vorgestellte allgemeine Fall "Verwenden des Funktionsnamens als Argument, damit Sie ihn nicht explizit übergeben müssen", und dies könnte in vielen Fällen nützlich sein, z. B. beim optionalen Rückruf jquery animate (). oder in Timeouts / Intervallen Rückrufen (dh Sie übergeben nur einen Funktionsnamen).

Sampiolin
quelle
2

Der Name der aktuellen Funktion und wie sie erhalten werden kann, scheint sich in den letzten 10 Jahren geändert zu haben, seit diese Frage gestellt wurde.

Da ich kein professioneller Webentwickler bin, der alle Historien aller Browser kennt, die jemals existiert haben, funktioniert dies für mich in einem Chrome-Browser von 2019 folgendermaßen:

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

Einige der anderen Antworten stießen auf Chromfehler in Bezug auf strengen Javascript-Code und so weiter.

BitTickler
quelle
1

Da Sie eine Funktion mit dem Namen geschrieben haben foound wissen, myfile.jswarum Sie diese Informationen dynamisch abrufen müssen?

arguments.callee.toString()Davon abgesehen können Sie innerhalb der Funktion (dies ist eine Zeichenfolgendarstellung der gesamten Funktion) den Wert des Funktionsnamens neu ausdrücken.

Hier ist eine Funktion, die ihren eigenen Namen ausspuckt:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}
Andrew Hare
quelle
5
Ich arbeite an einer Fehlerbehandlungsroutine und möchte die aufrufende Funktion melden.
Sprugman
1

Eine Kombination der wenigen Antworten, die ich hier gesehen habe. (Getestet in 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);
}

Durch Aufrufen von randomFunction () wird eine Zeichenfolge benachrichtigt, die den Funktionsnamen enthält.

JS Fiddle Demo: http://jsfiddle.net/mjgqfhbe/

buddamus
quelle
1

Die Informationen sind aktuell für das Jahr 2016.


Ergebnisse für die Funktionsdeklaration

Ergebnis in der Oper

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

Ergebnis im 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

Ergebnis im 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

Funktioniert nicht im Firefox. Ungetestet auf dem IE und dem Edge.


Ergebnisse für Funktionsausdrücke

Ergebnis im NodeJS

> var func11 = function(){
...     console.log('Function name:', arguments.callee.name)
... }; func11();
Function name: func11

Ergebnis im Chrome

var func11 = function(){
    console.log('Function name:', arguments.callee.name)
}; func11();
Function name: func11

Funktioniert nicht in Firefox, Opera. Ungetestet auf dem IE und dem Edge.

Anmerkungen:

  1. Anonyme Funktion macht keinen Sinn zu überprüfen.
  2. Testumgebung

~ $ 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
quelle
1
(function f() {
    console.log(f.name);  //logs f
})();

Typoskript-Variation:

function f1() {} 
function f2(f:Function) {
   console.log(f.name);
}

f2(f1);  //Logs f1

Hinweis Nur bei ES6 / ES2015-kompatiblen Motoren verfügbar. Weitere Informationen finden Sie unter

Ole
quelle
0

Hier ist ein Einzeiler:

    arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '')

So was:

    function logChanges() {
      let whoami = arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '');
      console.log(whoami + ': just getting started.');
    }
VRMBW
quelle
0

Dies ist eine Variante von Igor Ostroumovs Antwort:

Wenn Sie es als Standardwert für einen Parameter verwenden möchten, müssen Sie einen Aufruf der zweiten Ebene an 'caller' in Betracht ziehen:

function getFunctionsNameThatCalledThisFunction()
{
  return getFunctionsNameThatCalledThisFunction.caller.caller.name;
}

Dies würde dynamisch eine wiederverwendbare Implementierung in mehreren Funktionen ermöglichen.

function getFunctionsNameThatCalledThisFunction()
{
  return getFunctionsNameThatCalledThisFunction.caller.caller.name;
}

function bar(myFunctionName = getFunctionsNameThatCalledThisFunction())
{ 
  alert(myFunctionName);
}

// pops-up "foo"
function foo()
{
  bar();
}

function crow()
{
  bar();
}

foo();
crow();

Wenn Sie auch den Dateinamen möchten, finden Sie hier diese Lösung mit der Antwort von F-3000 auf eine andere Frage:

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
quelle
-1

Versuchen:

alert(arguments.callee.toString());
Deniz Dogan
quelle
3
Das würde die gesamte Funktion als String zurückgeben
Andy E
-7

Die Antwort ist kurz: alert(arguments.callee.name);

Basilikum
quelle
12
"nom" ist auf Französisch "name". Ändert sich diese Art von Detail zwischen Sprachversionen von Browsern? Das würde ich nicht glauben.
Argyle