5

Yes, I realize there are countless threads out there about this issue, for starters:

Get function name from function itself [duplicate]

Get function name from inside itself

Arguments.callee is deprecated - what should be used instead?

But the problem with the answers given is arguments.callee is deprecated. All of the answers say to just give your function a name. However, from what I can tell, that does not fix my problem. Say I have the following function:

function blah() {
  // arguments.callee.name is deprecated
  console.log('The function name is: ' + arguments.callee.name + '.');
}

But because that's deprecated, I shouldn't be using it, so what should I be using instead? Is there any way I can access the function name when inside the function itself, or am I just out of probability here?

If it makes things easier, I am using the framework Ext JS, but I haven't found a way of knowing the function's name. If not, is there a jQuery approach? I'm desperate here.

Community
  • 1
  • 1
incutonez
  • 3,241
  • 9
  • 43
  • 92
  • 1
    Is there a case you can't hardcode the function name? I agree it'd be nice to be able to get it programatically, but is it necessary? – Raekye Oct 21 '13 at 18:54
  • Well, yes. I'm trying to create some sort of logging mechanism, and I don't want to have to call the logging mechanism with a set name... I just want it to know the name. It makes more sense doing it this way because it's dynamic. If the function name changes, I might forget to change it for the logger. – incutonez Oct 21 '13 at 18:57
  • 2
    It might be easier to look at some of the stack trace visibility mechanisms available in modern browsers. They're not mutually compatible, but it'd probably be cleaner because you wouldn't have to explicitly pass in *anything*. – Pointy Oct 21 '13 at 19:08
  • 1
    Yeah, I saw the whole stack trace approach before posting this question, but it seems like major overkill. I don't understand why something so simple is basically impossible. – incutonez Oct 21 '13 at 19:26

2 Answers2

2

You can provoke an exception and examine the stack trace.

The following proof of context works in the Chrome browser:

function test () {
  try { [].undef () } catch (e) {
     console.log (e.stack.split ('\n')[1].split (/\s+/)[2]);
  }
}

For a more robust implementation consult http://www.eriwen.com/javascript/js-stack-trace/ which provides a full stack trace in any browser.

A more modern and comprehensive stack trace analyzer is http://stacktracejs.com

HBP
  • 15,685
  • 6
  • 28
  • 34
0

With some poking around, I came up with this SO thread, so building on top of that, I made a very very hacky solution that works (in both Chrome and FF... not sure about IE, but I doubt it works). Warning: this is very specific to my own use, so your mileage will definitely vary. Anyway, this is my code:

getLogLocation: function() {
  var ua = navigator.userAgent;
  var isFF = ua.search(/firefox/i) !== -1 ? true : false;
  var isChrome = ua.search(/chrome/i) !== -1 ? true : false;
  if (isFF || isChrome) {
    var stack = Error().stack,
        cname = '',
        funcPattern,
        classPattern = /.*\/(.*)\.js/;  // looking for something between the last backslash and .js
    if (stack) {
      var stacks = stack.split('\n');
      if (stacks) {
        var theStack;
        // the browsers create the stack string differently
        if (isChrome) {
          // the stack has getClassName, then logMessage, then our calling class, but Chrome has some added garbage
          theStack = stacks[4];
          funcPattern = /.*\.(.*)\s+\(/;   // looking for something between a period and the first paren
        }
        else {
          theStack = stacks[2];
          funcPattern = /^\.*(.*)\@/;  // looking for something between a period and an @ symbol
        }
        var matches = theStack.match(classPattern);
        cname = matches[1] + '::';
        matches = theStack.match(funcPattern);
        cname += matches[1] + ':';
      }
    }
    return cname;
  }
}

And if you're curious what my stack looks like, here're the relevant lines:

Firefox (cut out a lot of lines)

".getClassName@http://127.0.0.1/javascripts/app/mixins/ConsoleMixin.js?_dc=1383836090216:72
.logMessage@http://127.0.0.1/javascripts/app/mixins/ConsoleMixin.js?_dc=1383836090216:31
.constructor@http://127.0.0.1/javascripts/app/BaseController.js?_dc=1383836089659:39
..."

Chrome (the first 2 lines are the garbage I have to accommodate for... after that, it's similar to FF's Stack string)

"Error
    at Error (<anonymous>)
    at Ext.define.getLogLocation (http://127.0.0.1/javascripts/app/mixins/ConsoleMixin.js?_dc=1383836606405:72:19)
    at Ext.define.logMessage (http://127.0.0.1/javascripts/app/mixins/ConsoleMixin.js?_dc=1383836606405:31:24)
    at new Ext.define.constructor (http://127.0.0.1/javascripts/app/BaseController.js?_dc=1383836606265:39:14)
    ..."

See this jsFiddle for a working example... had to change the stack values because we're no longer in Ext JS.

Now, a little explanation. getLogLocation resides as a function in an Ext JS class (ConsoleMixin), and another function inside of ConsoleMixin (logMessage) calls getLogLocation, and logMessage is called by our outer class's function (constructor), which is why I have to compensate for the first 2 stack values. Like I said, very hacky and specific to my need, but hopefully someone can make use of it.

Community
  • 1
  • 1
incutonez
  • 3,241
  • 9
  • 43
  • 92