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

Viewed 165021

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.

20 Answers

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.

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?

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"

This should do it:

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

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

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

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

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

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.

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

Try:

alert(arguments.callee.toString());
Related