Can I get the name of the currently running function in JavaScript?

185.5k views Asked by At

Is it possible to do this:

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

I've got the Dojo and jQuery frameworks in my stack, so if either of those make it easier, they're available.

21

There are 21 answers

7
Matt On BEST ANSWER

In ES5 and above, there is no access to that information.

In older versions of JS you can get it by using arguments.callee.

You may have to parse out the name though, as it will probably include some extra junk. Though, in some implementations you can simply get the name using arguments.callee.name.

Parsing:

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

   alert(myName);
}

Source: Javascript - get current function name.

0
Laimonas On

According to MDN

Warning: The 5th edition of ECMAScript (ES5) forbids use of arguments.callee() in strict mode. Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself.

As noted this applies only if your script uses "strict mode". This is mainly for security reasons and sadly currently there's no alternative for this.

0
buddamus On

A combination of the few responses I've seen here. (Tested 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);
}

Calling randomFunction() will alert a string that contains the function name.

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

1
Anthony On

Here's a way that will work:

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

Then in your 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);
  });

});

Note that the third test will only work if the test is located in /util/functions

0
ya.teck On

When a function is a constructor the name can be obtain as follows.

function Example() {
  console.log(new.target.name);
}


new Example();
1
Ole On
(function f() {
    console.log(f.name);  //logs f
})();

Typescript variation:

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

f2(f1);  //Logs f1

Note only available in ES6/ES2015 compliant engines. For more see

0
Sampiolin On

Another use case could be an event dispatcher bound at 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);

The advantage here is the dispatcher can be easily reused and doesn't have to receive the dispatch queue as an argument, instead it comes implicit with the invocation name...

In the end, the general case presented here would be "using the function name as an argument so you don't have to pass it explicitly", and that could be useful in many cases, such as the jquery animate() optional callback, or in timeouts/intervals callbacks, (ie you only pass a funcion NAME).

0
Eazicoding On

As arguments.callee.name is non-standard, and forbidden in ECMAScript 5 strict mode (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee), a simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.

{
  function foo() {
    alert (a.name);
  }; let a = foo
}
{
  function foo2() {
    alert(a.name)
  }; let a = foo2
};
foo();//logs foo
foo2();//logs foo2

Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.

1
Basil On

The answer is short: alert(arguments.callee.name);

0
Amir Hossein Baghernezad On

The arguments object is a local variable available within all non-arrow functions.
You can refer to a function's arguments inside that function by using its arguments object.
It has entries for each argument the function was called with, with the first entry's index at 0.

So you can basically use arguments.callee.name but inside named functions like this one:

function i_have_a_name() {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
My name is: i_have_a_name

Unfortunately it is not usable inside arrow functions:

const i_have_a_name = () => {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
Uncaught ReferenceError: arguments is not defined
    at i_have_a_name (REPL3:2:32)

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

0
VRMBW On

Here is a one liner:

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

Like this:

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

This a variant of Igor Ostroumov's answer:

If you would like to use it as a default value for a parameter, you need to consider a second level call to 'caller':

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

This would dynamically allow for a reusable implementation in multiple functions.

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

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

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

function crow()
{
  bar();
}

foo();
crow();

If you want the file name too, here is that solution using the answer from F-3000 on another 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
PADYMKO On

Information is actual on 2016 year.


Results for function declaration

Result in the 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

Result in the 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

Result in the 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

Does not work in the Firefox. Untested on the IE and the Edge.


Results for function expressions

Result in the NodeJS

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

Result in the Chrome

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

Does not work in the Firefox, Opera. Untested on the IE and the Edge.

Notes:

  1. Anonymous function does not to make sense to check.
  2. Testing environment

~ $ 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
Jon49 On

An updated answer to this can can be found over at this answer: https://stackoverflow.com/a/2161470/632495

and, if you don't feel like clicking:

function test() {
  var z = arguments.callee.name;
  console.log(z);
}
3
Max Heiber On

The getMyName function in the snippet below returns the name of the calling function. It's a hack and relies on non-standard feature: Error.prototype.stack. Note that format of the string returned by Error.prototype.stack is implemented differently in different engines, so this probably won't work everywhere:

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

About other solutions: arguments.callee is not allowed in strict mode and Function.prototype.calleris non-standard and not allowed in strict mode.

1
Andrew Hare On

Since you have written a function named foo and you know it is in myfile.js why do you need to get this information dynamically?

That being said you can use arguments.callee.toString() inside the function (this is a string representation of the entire function) and regex out the value of the function name.

Here is a function that will spit out its own name:

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

Try:

alert(arguments.callee.toString());
2
fforw On

For non-anonymous functions

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

But in case of an error handler the result would be the name of the error handler function, wouldn't it?

3
Andy E On

This should do it:

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

For the caller, just use caller.toString().

2
James Hugard On

This has to go in the category of "world's ugliest hacks", but here you go.

First up, printing the name of the current function (as in the other answers) seems to have limited use to me, since you kind of already know what the function is!

However, finding out the name of the calling function could be pretty useful for a trace function. This is with a regexp, but using indexOf would be about 3x faster:

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

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

me();
6
Igor Ostroumov On

All what you need is simple. Create function:

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

After that whenever you need, you simply use:

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

foo() 
// Logs: "foo"