Posso ottenere il nome della funzione attualmente in esecuzione in JavaScript?


185

È possibile farlo:

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

Ho i framework Dojo e jQuery nel mio stack, quindi se uno di questi lo rende più semplice, sono disponibili.

Risposte:


196

In ES5 e versioni successive, non è possibile accedere a tali informazioni.

Nelle versioni precedenti di JS puoi ottenerlo utilizzando arguments.callee .

Tuttavia, potresti dover analizzare il nome, poiché probabilmente includerà un po 'di spazzatura. Tuttavia, in alcune implementazioni puoi semplicemente ottenere il nome usandoarguments.callee.name .

Analisi:

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

   alert(myName);
}

Fonte: Javascript: ottieni il nome della funzione corrente .


In realtà, prestando più attenzione alla tua domanda, sembra che potresti desiderare la spazzatura extra :)
Matt,

23
@Andrew - Hai ragione, avrei dovuto dirlo. È stata una rapida copia / incolla / pulizia di qualcosa che avevo già aggiunto ai segnalibri e una svista da parte mia. Grazie per averlo aggiunto al mio post.
Matt,

81
Interruzioni nella modalità rigorosa ES5.
Raynos,

4
Oh ... ecco perché la gente mi ha sempre battuto sulla velocità di rispondere. Non ci avevo pensato.
Erik Reppen,

9
se stai usando un oggetto letterale per i tuoi metodi e nessun nome di metodo effettivo, allora questo non funzionerà come argomenti.callee si comporta come una funzione anonima che non porterà alcun nome di funzione. Dovresti assicurarti di aggiungere quel nome di funzione due volte. Dai un'occhiata a questo esempio di jsfiddle : jsfiddle.net/ncays . un altro problema con questo, tuttavia, è che arguments.calleenon è consentito in modalità rigorosa.
Hellatan,

75

Per funzioni non anonime

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

Ma nel caso di un gestore degli errori il risultato sarebbe il nome della funzione del gestore degli errori, no?


2
Funziona alla grande in Chrome. Molto meglio della risposta accettata.
B Seven,

1
Vale la pena ricordare: eslint.org/docs/rules/no-caller > "deprecato nelle future versioni di JavaScript e il loro uso è vietato in ECMAScript 5 in modalità rigorosa."
Jeremy,

44

Tutto ciò di cui hai bisogno è semplice. Crea funzione:

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

Dopodiché ogni volta che ne hai bisogno, usi semplicemente:

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

foo() 
// Logs: "foo"

3
Grazie, questo è molto più elegante dell'analisi di una stringa.
modle13

1
Sembra essere la risposta migliore!
Sergey,

Perfetto. Questo è quando JS non ha costanti native come PHP ha con costanti magiche ...
stamster

Chrome mi dà un errore di tipo perché la proprietà 'name' non esiste sul chiamante. Tuttavia, l'ispezione ha rivelato che ha funzionato:function getFuncName() { return getFuncName.name }
Tom Anderson il

@TomAnderson con la tua modifica, ora ricevi il nome getFuncNameanziché il nome del suo chiamante.
Mark McKenna

30

Secondo MDN

Avvertenza: la quinta edizione di ECMAScript (ES5) vieta l'uso di argument.callee () in modalità rigorosa. Evita di usare argomenti.callee () dando un nome alle espressioni di funzione o usa una dichiarazione di funzione dove una funzione deve chiamarsi.

Come notato, questo vale solo se lo script utilizza la "modalità rigorosa". Ciò è principalmente per motivi di sicurezza e purtroppo attualmente non esiste alternativa per questo.


21

Questo dovrebbe farlo:

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

Per il chiamante, basta usare caller.toString().


8
Questo ha funzionato per me, ma penso che ci sia un refuso nella tua regexp. Ho dovuto eliminare la barra rovesciata prima del[
declan

4
@declan: sì, hai ragione. È sorprendente che nessun altro abbia sottolineato che in quasi 3 anni questa risposta è stata qui :-)
Andy E

@AndyE probabilmente nessuno lo ha sottolineato perché quando vediamo una regexp, entriamo in TL; modalità DR e cerchiamo altre risposte;)
BitTickler

11

Questo deve rientrare nella categoria degli "hack più brutti del mondo", ma ecco qui.

Innanzitutto, stampando il nome della corrente funzione (come nelle altre risposte) mi sembra avere un uso limitato, dato che sai già qual è la funzione!

Tuttavia, scoprire il nome della funzione chiamante potrebbe essere molto utile per una funzione di traccia. Questo è con una regexp, ma l'uso di indexOf sarebbe circa 3 volte più veloce:

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

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

me();

soluzione interessante, ma FYI Funzione # chiamante è sviluppatore
Max Heiber

Conoscere il nome della funzione corrente può essere essenziale se quella funzione viene creata dinamicamente da un database e necessita di informazioni di contesto all'interno della funzione che è stata codificata per il nome della funzione.
Paul Chernoch,

9

Ecco un modo che funzionerà:

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

Quindi nei tuoi test:

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

});

Si noti che il terzo test funzionerà solo se il test si trova in / util / funzioni


7

La getMyNamefunzione nello snippet seguente restituisce il nome della funzione chiamante. Si tratta di un hack e si basa su non standard funzione: Error.prototype.stack. Si noti che il formato della stringa restituito da Error.prototype.stackviene implementato in modo diverso nei diversi motori, quindi probabilmente non funzionerà ovunque:

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

Informazioni su altre soluzioni: arguments.callee non è consentito in modalità rigorosa e nonFunction.prototype.caller è standard e non è consentito in modalità rigorosa .


estendere questo per mostrare anche la posizione nella funzione e supportare le funzioni anonime con: .replace (/ ^ \ s + at \ s (. +?) (?: \ s. *: |:) (. *?): (. * ?))? $ / g, '$ 1 ($ 2: $ 3)')
kofifus

Anche Function.prototype.caller non è consentito in modalità rigorosa.
fijiaaron,

1
Funziona perfettamente anche con le funzioni freccia, risposta sottovalutata
Hao Wu,

3

Un altro caso d'uso potrebbe essere un dispatcher di eventi associato al runtime:

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

Il vantaggio qui è che il dispatcher può essere facilmente riutilizzato e non deve ricevere la coda di invio come argomento, ma è implicito con il nome dell'invocazione ...

Alla fine, il caso generale presentato qui sarebbe "usare il nome della funzione come argomento in modo da non doverlo passare esplicitamente", e ciò potrebbe essere utile in molti casi, come il callback opzionale jquery animate (), o in timeout / intervalli richiamate, (ovvero si passa solo una funzione NAME).


2

Il nome della funzione corrente e come può essere ottenuto sembra essere cambiato negli ultimi 10 anni, da quando è stata posta questa domanda.

Ora, non essendo uno sviluppatore web professionista che conosce tutte le storie di tutti i browser che siano mai esistiti, ecco come funziona per me in un browser Chrome 2019:

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

Alcune delle altre risposte si sono imbattute in alcuni errori di Chrome sul codice javascript rigoroso e quant'altro.


1

Dal momento che hai scritto una funzione denominata fooe sai che è myfile.jsperché hai bisogno di ottenere queste informazioni in modo dinamico?

Detto questo, è possibile utilizzare arguments.callee.toString()all'interno della funzione (questa è una rappresentazione in forma di stringa dell'intera funzione) e ripetere il valore del nome della funzione.

Ecco una funzione che sputerà il suo nome:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}

5
Sto lavorando a un gestore di errori e desidero segnalare la funzione di chiamata.
Sprugman,

1

Una combinazione delle poche risposte che ho visto qui. (Testato 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);
}

La chiamata di randomFunction () avviserà una stringa che contiene il nome della funzione.

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



1

Le informazioni sono aggiornate al 2016 anno.


Risultati per la dichiarazione di funzione

Risultato nell'opera

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

Risultato in 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

Risultato in 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

Non funziona in Firefox. Non testato su IE e Edge.


Risultati per le espressioni di funzione

Risultato in NodeJS

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

Risultato in Chrome

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

Non funziona in Firefox, Opera. Non testato su IE e Edge.

Appunti:

  1. La funzione anonima non ha senso controllare.
  2. Ambiente di test

~ $ 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
})();

Variazione dattiloscritta:

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

f2(f1);  //Logs f1

Nota disponibile solo nei motori conformi a ES6 / ES2015. Per di più vedi


0

Ecco una fodera:

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

Come questo:

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

0

Questa è una variante di Igor Ostroumov risposta :

Se si desidera utilizzarlo come valore predefinito per un parametro, è necessario considerare una chiamata di secondo livello a "chiamante":

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

Ciò consentirebbe dinamicamente un'implementazione riutilizzabile in più funzioni.

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

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

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

function crow()
{
  bar();
}

foo();
crow();

Se vuoi anche il nome del file, ecco quella soluzione usando la risposta di F-3000 su un'altra domanda:

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

-1

Provare:

alert(arguments.callee.toString());

3
Ciò restituirebbe l'intera funzione come una stringa
Andy E,

-7

La risposta è breve: alert(arguments.callee.name);


12
"nom" è "nome" in francese. Questo tipo di dettagli cambia tra le versioni linguistiche dei browser? Non la penso così.
argyle,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.