57

Is it possible to see the callee/caller of a function when use strict is enabled?

'use strict';

function jamie (){
    console.info(arguments.callee.caller.name);
    //this will output the below error
    //uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
};

function jiminyCricket (){
   jamie();
}

jiminyCricket ();
Jamie Hutber
  • 26,790
  • 46
  • 179
  • 291
  • 4
    In general (with *very few* exceptions) if you want to do that - you are doing something wrong. Try to explain the *real problem* you want to solve wit this code. – zerkms Apr 11 '15 at 00:03
  • 2
    There is no alternative. The recommended way is to use the function name directly like `jamie.name // jamie`. But function names are often irrelevant, other than for debugging, they make no difference in your code, and relying on this functionality for something other than recursion is usually an XY problem. – elclanrs Apr 11 '15 at 00:03
  • 4
    To be honest, there isn't any real problem with my code, but I have a function aliasing `console.info` so `c = console.info` essentially. So when I console something with said function, it just shows in the console that it came from the same place every time. i wanted to output which function called it. Just for my being lazy and cool all rolled into one :D – Jamie Hutber Apr 11 '15 at 00:06
  • If it is for debugging, devtools do all of that for you. You can step in and out of function calls, place debugger statements and so on. – elclanrs Apr 11 '15 at 00:08
  • 1
    ye of course :) But that means pressing f11.... I don't wanna have to do anything more if a little bit of code could do this for me :p I'm a programmer.. Its the only reason I do this... I'm lazy – Jamie Hutber Apr 11 '15 at 00:11
  • 3
    [This MDN document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee) gives an explanation why it was removed from JS Strict Mode. Basically, the ability to use `arguments.callee` and `arguments.caller` made certain JS engine optimisations difficult/impossible. – Phylogenesis Apr 11 '15 at 00:13

5 Answers5

54

For what it's worth, I agree with the comments above. For whatever problem you're trying to solve, there are usually better solutions.

However, just for illustrative purposes, here's one (very ugly) solution:

'use strict'

function jamie (){
    var callerName;
    try { throw new Error(); }
    catch (e) { 
        var re = /(\w+)@|at (\w+) \(/g, st = e.stack, m;
        re.exec(st), m = re.exec(st);
        callerName = m[1] || m[2];
    }
    console.log(callerName);
};

function jiminyCricket (){
   jamie();
}

jiminyCricket(); // jiminyCricket

I've only tested this in Chrome, Firefox, and IE11, so your mileage may vary.

Tieme
  • 62,602
  • 20
  • 102
  • 156
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • 1
    ha great idea. Throw a error. It really isn't a big deal as such. Just would be nice to know where the console.log's are coming from. I don't see this as a problem? – Jamie Hutber Apr 11 '15 at 00:21
  • 3
    This worked well. We had to use the throw version instead of @inetphantom's solution because an embedded JavaScript engine we had to work with didn't populate Error().stack until it was thrown. – RomSteady Sep 07 '16 at 19:15
  • Hi, is there any way to get parameters of the caller function? – easa Aug 03 '17 at 19:29
  • @easa I don't think there would be a general solution for that. You'd really need to inspect the stack in a debugger. – p.s.w.g Aug 03 '17 at 23:03
  • @easa pass `this` to the function and you have everything you need! – inetphantom Nov 29 '18 at 13:53
  • 1
    you got an upvote because the ugliness yet cleverness made me laugh – Samer Murad May 27 '20 at 10:48
  • 1
    I don't think you have to throw the error, it should be enough just to run that regex on `new Error().stack` – Sandy Gifford Jun 29 '20 at 23:57
35

Please note that this should not be used in production. This is an ugly solution, which can be helpful for debugging, but if you need something from the caller, pass it as argument or save it into a accessible variable.

The short version of @p.s.w.g answer(without throwing an error, just instantiating one):

    let re = /([^(]+)@|at ([^(]+) \(/g;
    let aRegexResult = re.exec(new Error().stack);
    sCallerName = aRegexResult[1] || aRegexResult[2];

Full Snippet:

'use strict'

function jamie (){
    var sCallerName;
    {
        let re = /([^(]+)@|at ([^(]+) \(/g;
        let aRegexResult = re.exec(new Error().stack);
        sCallerName = aRegexResult[1] || aRegexResult[2];
    }
    console.log(sCallerName);
};

function jiminyCricket(){
   jamie();
};

jiminyCricket(); // jiminyCricket
Manav Kataria
  • 5,060
  • 4
  • 24
  • 26
inetphantom
  • 2,498
  • 4
  • 38
  • 61
  • The regex to match the name in the stack should probably be `([^(]+)` instead of `(\w+)` because spaces and punctuation are common. – maffews Jul 11 '17 at 19:20
  • 2
    You added a warning for production use... Hmmm... The function is not pure, indeed. But should that be a serious reason for not using it in production code? The code seems to be pretty stable (as far as I can judge). And a very interesting application would be in a logging method. In that case, passing the caller name in a parameter would be tedious, bloating and error-prone. So, as I see it, the decision of why and when certain code should be used in production or not mainly depends on the software design and some common sense. I will *gladly* use it in production code if it works for me. – Bart Hofland Aug 28 '19 at 06:56
  • 1
    Ah. I see now. The [`Error.prototype.stack`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack) property is officially marked as non-standard and implementation-specific. – Bart Hofland Aug 28 '19 at 07:22
  • 1
    From [the `Error.prototype.stack` documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack): "Different browsers set this value at different times. For example, Firefox sets it when creating an Error object, while PhantomJS sets it only when throwing the Error, and archived MSDN docs also seem to match the PhantomJS implementation." So [p.s.w.g](https://stackoverflow.com/users/1715579)'s answer (involving creating, throwing and catching an Error) might be more robust anyway... – Bart Hofland Aug 28 '19 at 07:29
  • @BartHofland I still wouldn't use it - Where is the point of logging who called a function? If there is an error - log that error. – inetphantom Aug 28 '19 at 11:46
  • Yes, I agree. You are right about that. When catching an error, that error will already include a stack trace. So in that case, I would not need to explicitly access the stack trace. Yesterday I have been investigating this stack trace issue somewhat further and came to the conclusion, that *if* I do need to handle the stack trace, I personally will most likely use a specialized 3rd party package for that. Especially when code will be deployed in (public) production environments. – Bart Hofland Aug 30 '19 at 08:38
12

It does not worked for me Here is what I finally do, just in case it helps someone

function callerName() {
  try {
    throw new Error();
  }
  catch (e) {
    try {
      return e.stack.split('at ')[3].split(' ')[0];
    } catch (e) {
      return '';
    }
  }

}
function currentFunction(){
  let whoCallMe = callerName();
  console.log(whoCallMe);
}
Benamar
  • 845
  • 8
  • 3
  • 1
    Cany ou please explain why this worked for you and the other solutions did not? – Noel Widmer Jun 05 '17 at 10:37
  • I had something like exception on aRegexResult[1] index out of range – Benamar Jun 06 '17 at 11:22
  • aregexResult[1] index out of range is because names in the call stack that don't match `\w+` are skipped. You should use `[^(]+` instead. – maffews Jul 11 '17 at 19:22
  • This solution should work much **faster than Regex**. – Serg Oct 20 '18 at 16:38
  • This seems to work the best for an Angular/TypeScript configuration. – Russ Nov 26 '20 at 05:51
  • @Sergei is it important to log the error as fast as possible? Isn't this quite fast anyway? Are you loggingn a whole book? I doubt you should care about performance here - could be better on your approach is readability. – inetphantom Mar 29 '22 at 07:16
7

You can get a stack trace using:

console.trace()

but this is likely not useful if you need to do something with the caller.

See https://developer.mozilla.org/en-US/docs/Web/API/Console/trace

Larry
  • 1,238
  • 2
  • 20
  • 25
-1
  functionName() {
    return new Error().stack.match(/ at (\S+)/g)[1].get(/ at (.+)/);
  }

  // Get - extract regex
  String.prototype.get = function(pattern, defaultValue = "") {
    if(pattern.test(this)) {
      var match = this.match(pattern);
      return match[1] || match[0];
    }
    return defaultValue; // if nothing is found, the answer is known, so it's not null
  }
toddmo
  • 20,682
  • 14
  • 97
  • 107