234

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.

Bourbia Brahim
  • 14,459
  • 4
  • 39
  • 52
sprugman
  • 19,351
  • 35
  • 110
  • 163
  • Does this answer your question? [Get current function name in strict mode](https://stackoverflow.com/questions/38435450/get-current-function-name-in-strict-mode) – Michael Freidgeim Sep 26 '20 at 01:37

21 Answers21

229

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.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
Matt
  • 2,619
  • 1
  • 17
  • 14
  • Actually, actually paying more attention to your question, it sounds like you might want the extra junk :) – Matt Jun 18 '09 at 15:17
  • 91
    Breaks in ES5 strict mode. – Raynos Jul 01 '11 at 13:48
  • 4
    Oh... that's why people always beat me on the speed to reply. I hadn't thought of that. – Erik Reppen Jul 06 '12 at 13:56
  • 9
    if you are using an object literal for your methods and no actual method name, then this will not work as arguments.callee acts like an anonymous function which will not carry any function name. You would have to make sure you add that function name twice. Take a look at this jsfiddle example: http://jsfiddle.net/ncays/. another issue with this, though, is that `arguments.callee` is not allowed under strict mode. – hellatan May 28 '13 at 15:48
  • 1
    You could just use `argument.callee.name` on some environments. Works on Chrome. – SOFe Dec 21 '17 at 14:32
  • @SOFe `ReferenceError: argument is not defined` – Manohar Reddy Poreddy Nov 12 '20 at 16:08
  • I meant `arguments` – SOFe Nov 12 '20 at 16:59
92

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?

fforw
  • 5,391
  • 1
  • 18
  • 17
  • 2
    Works great in Chrome. Much better than accepted answer. – B Seven Jun 12 '16 at 02:43
  • 5
    Worth bearing in mind: https://eslint.org/docs/rules/no-caller > "deprecated in future versions of JavaScript and their use is forbidden in ECMAScript 5 while in strict mode." – Jeremy Feb 26 '20 at 19:20
81

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"
Igor Ostroumov
  • 927
  • 6
  • 2
38

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.

Laimonas
  • 5,781
  • 2
  • 19
  • 20
28

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.

Max Heiber
  • 14,346
  • 12
  • 59
  • 97
21

This should do it:

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

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

Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 8
    This worked for me but I think there's a typo in your regexp. I had to take out the backslash before the `[` – declan Feb 13 '12 at 03:50
  • 4
    @declan: yep, you're right. It's surprising nobody else has pointed that out in the almost 3 years this answer has been here :-) – Andy E Feb 13 '12 at 15:13
  • 2
    @AndyE probably no one pointed it out because once we see a regexp, we enter TL;DR mode and look for other answers ;) – BitTickler Nov 08 '19 at 22:57
19

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

Anthony
  • 13,434
  • 14
  • 60
  • 80
11

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();
Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
James Hugard
  • 3,232
  • 1
  • 25
  • 36
  • cool solution, but FYI Function#caller is non-standard https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller – Max Heiber Sep 05 '16 at 20:36
  • Knowing the name of the current function can be essential if that function is being created dynamically from a database and needs context information inside the function that is keyed to the function name. – Paul Chernoch Aug 22 '18 at 18:51
5

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

3

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

Sampiolin
  • 31
  • 1
3
(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

Ole
  • 41,793
  • 59
  • 191
  • 359
  • Note that you shouldn't do this if you intend to use a minifier like Terser, which may change the function names. See ; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name – Andrew Nov 10 '20 at 22:27
2

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.

Eazicoding
  • 191
  • 9
1

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]);             
}
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
1

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/

buddamus
  • 400
  • 4
  • 8
1

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);
}
Community
  • 1
  • 1
Jon49
  • 4,444
  • 4
  • 36
  • 73
1

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
PADYMKO
  • 4,217
  • 2
  • 36
  • 41
0

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.');
    }
VRMBW
  • 1
  • 1
0

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();
}
SMAG
  • 652
  • 6
  • 12
0

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

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


new Example();
ya.teck
  • 2,060
  • 28
  • 34
-1

Try:

alert(arguments.callee.toString());
Deniz Dogan
  • 25,711
  • 35
  • 110
  • 162
-6

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

Jayant Bhawal
  • 2,044
  • 2
  • 31
  • 32
Basil
  • 1
  • 13
    "nom" is "name" in French. Does this sort of detail change between language versions of browsers? I wouldn't think so. – argyle Dec 16 '11 at 18:36