web-dev-qa-db-fra.com

Puis-je obtenir le nom de la fonction en cours d'exécution en JavaScript?

Est-il possible de faire cela:

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

J'ai les frameworks Dojo et jQuery dans ma pile, donc si cela facilite les choses, ils sont disponibles.

154
sprugman

Vous devriez pouvoir l'obtenir en utilisant arguments.callee.

Cependant, vous devrez peut-être analyser le nom, car il comprendra probablement des fichiers indésirables. Cependant, dans certaines implémentations, vous pouvez simplement obtenir le nom en utilisant arguments.callee.name.

Analyse:

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

   alert(myName);
}

Source: Javascript - Obtenir le nom de la fonction actuelle .

163
Matt

Pour les fonctions non anonymes 

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

Mais en cas de gestionnaire d'erreur, le résultat serait le nom de la fonction de gestionnaire d'erreur, n'est-ce pas?

56
fforw

Selon MDN

Attention: La 5ème édition de ECMAScript (ES5) interdit l'utilisation de arguments.callee () en mode strict. Évitez d'utiliser arguments.callee () en attribuant un nom aux expressions de fonction ou en utilisant une déclaration de fonction dans laquelle une fonction doit s'appeler elle-même.

Comme indiqué précédemment, cela ne s'applique que seulement si votre script utilise le "mode strict". C’est principalement pour des raisons de sécurité et, malheureusement, il n’existe actuellement aucune alternative.

23
Laimis

Tout ce dont vous avez besoin est simple… .. Créer une fonction:

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

Après cela chaque fois que vous avez besoin, vous utilisez simplement:

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

foo() 
// Logs: "foo"
21
Igor Ostroumov

Cela devrait le faire:

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

Pour l'appelant, utilisez simplement caller.toString().

21
Andy E

Cela doit entrer dans la catégorie des "hack les plus laids du monde", mais c'est parti.

Tout d’abord, imprimer le nom de la fonction current (comme dans les autres réponses) semble avoir une utilité limitée pour moi, car vous savez déjà en quelque sorte la fonction!

Cependant, connaître le nom de la fonction-appelant peut être très utile pour une fonction de trace. C'est avec une expression rationnelle, mais utiliser indexOf serait environ 3 fois plus rapide:

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

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

me();
10
James Hugard

Voici une façon qui fonctionnera:

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

Puis dans vos 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);
  });

});

Notez que le troisième test ne fonctionnera que si le test est situé dans/util/functions

8
Antoine

Un autre cas d'utilisation pourrait être un répartiteur d'événements lié au moment de l'exécution:

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

L'avantage ici est que le répartiteur peut être facilement réutilisé et qu'il n'est pas nécessaire de recevoir la file d'attente de distribution en tant qu'argument, mais qu'il est implicite avec le nom d'invocation ...

En fin de compte, le cas général présenté ici serait "d'utiliser le nom de la fonction en tant qu'argument pour éviter de le passer explicitement", ce qui peut être utile dans de nombreux cas, tels que le rappel facultatif jquery animate (), ou dans des rappels de timeouts/intervalles (c’est-à-dire que vous ne transmettez qu’un nom de fonction).

3
Sampiolin

La fonction getMyName de l'extrait ci-dessous renvoie le nom de la fonction appelante. C'est un hack et repose sur non standard feature: Error.prototype.stack. Notez que le format de la chaîne renvoyée par Error.prototype.stack est implémenté différemment dans différents moteurs, donc cela ne fonctionnera probablement pas partout:

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

À propos des autres solutions: arguments.calleen'est pas autorisé en mode strict et Function.prototype.calleris n'est pas standard et n'est pas autorisé en mode strict .

2
Max Heiber

Puisque vous avez écrit une fonction nommée foo et que vous savez qu'elle est dans myfile.js, pourquoi devez-vous obtenir cette information de manière dynamique?

Cela étant dit, vous pouvez utiliser arguments.callee.toString() dans la fonction (il s’agit d’une représentation sous forme de chaîne de la fonction entière) et regex la valeur du nom de la fonction.

Voici une fonction qui va cracher son propre nom:

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

Vous trouverez une réponse à jour à cette réponse à l'adresse suivante: https://stackoverflow.com/a/2161470/632495

et, si vous n'avez pas envie de cliquer:

function test() {
  var z = arguments.callee.name;
  console.log(z);
}
1
Jon49

Une combinaison des quelques réponses que j'ai vues ici. (Testé en 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);
}

L'appel de randomFunction () alertera une chaîne contenant le nom de la fonction.

Démo de JS Fiddle: http://jsfiddle.net/mjgqfhbe/

0
buddamus
(function f() {
    console.log(f.name);  //logs f
})();

Variation TypeScript:

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

f2(f1);  //Logs f1

Remarque disponible uniquement dans les moteurs conformes ES6/ES2015. Pour plus voir

0
Ole

Les informations sont réelles sur l'année 2016.


Résultats pour la déclaration de fonction

Résultat à l'Opéra

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

Résultat dans le 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

Résultat dans le 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

Ne fonctionne pas dans Firefox. Non testé sur IE et Edge.


Résultats pour les expressions de fonction

Résultat dans le NodeJS

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

Résultat dans le Chrome

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

Ne fonctionne pas dans Firefox, Opera. Non testé sur IE et Edge.

Remarques:

  1. La fonction anonyme n'a pas de sens à vérifier.
  2. Environnement de 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
0
Seti Volkylany

C'est une variante de d'Igor Ostroumov réponse:

Si vous souhaitez l'utiliser comme valeur par défaut pour un paramètre, vous devez envisager un appel de second niveau à 'caller':

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

Cela permettrait dynamiquement une implémentation réutilisable dans plusieurs fonctions.

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

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

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

function crow()
{
  bar();
}

foo();
crow();

Si vous voulez aussi le nom du fichier, voici cette solution en utilisant la réponse de F-3000 sur une autre question:

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

Voici un one liner:

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

Comme ça:

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