How do you find out the caller function in JavaScript?
Asked Answered
H

38

1059
function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

Is there a way to find out the call stack?

Heeley answered 11/11, 2008 at 9:4 Comment(13)
I hope this is just to aid you in debugging. Varying behaviour based on the caller is a bad idea.Riley
When would this be useful for debugging?Monostich
@AndersonGreen when you've got, for example, a default template render method and see it's being called twice. Rather than combing through 1000s of LoC or arduous stepping through with the debugger, you can just see what was the stack at the time.Chicken
to see the stack trace use console.trace() for chrome. don't know about others thoughGodric
This must not be used to "vary" behaviour (1st comment). Think of the concept of middlewares where you just might want to check if the caller calls another named middleware ...Barnsley
@Godric Using stacktracejs.com can be a option too, cross browser of course, cuz it's pure Javascript, so no Jquery or other dependant.Nibelungenlied
For debug, it can also be usefull when dealing with events. When pausing to trace, you actually mess with the chain of event you want to check. That console.trace() saved my day. It works on IE11, Firefox and Chrome.Johnston
This could be useful too if you need the full stack trace: #6716071Bontebok
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1]) for ES6 or 'strict mode'. This statement throws an exception if there is no Caller.Godsey
Why is this a bad idea?Stomatal
"I hope this is just to aid you in debugging. Varying behaviour based on the caller is a bad idea." Why we should be able to downvote comments. He didn't ask if it was a good idea, and you're also wrong. It's immensely useful in other languages like C# when you want to notify subscribers of a property change without magic strings that don't refactor easily.Lueluebke
While it's generally a bad idea, it's not always specifically a bad idea. To @PeterMoore's point, it's highly valuable in pub-sub / observer libraries, and not at all an anti-pattern in those cases. Also, labeling an idea "bad" without providing reasoning isn't helpful.Butts
@Butts I just had a thought after seeing your mention. I wonder if this could be accomplished - at least in Typescript - with a compile-time transform. There's an excellent nameof library (github.com/dsherret/ts-nameof) that does something slightly similar. Something to think about!Lueluebke
W
1078

Note that this solution is deprecated and should no longer be used according to MDN documentation

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller


function Hello()
{
    alert("caller is " + Hello.caller);
}

Note that this feature is non-standard, from Function.caller:

Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.


The following is the old answer from 2008, which is no longer supported in modern Javascript:

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}
Well answered 11/11, 2008 at 9:7 Comment(21)
arguments.callee.caller.name will get the function's name.Watermelon
it throws arguments.callee.caller is null in a Mozilla (xulrunner 1.9.2) applicationCarrol
@Incognito as you've no doubt figured out by now, any function can be cast to a string. I can't think of any tricks at all... View source.Misrepresent
"'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them" - they're deprecated in ES5 and removed in strict mode.Cauley
arguments.callee.caller.name didn't work for me so to just get the caller function name returned I used this: 'arguments.callee.caller.toString().split('(')[0]'Rammer
It will only work, if you are not using strict mode. So removing 'use strict'; might help.Eadith
Hmm, arguments can't be used in strict mode? Then how can I use variable argument list without it?Ratib
arguments CAN be accessed from within a function in strict mode, it would be stupid to deprecate that. just not from function.arguments from the outside. Also, if you have a named argument, the arguments[i] form of it will not track changes you make to the named version inside the function.Ectoblast
This method has become obsolete since this post was listed in 2011. The preferred method is now Function.caller, (as of 2015).Live
@Live Do you have a source (e.g a url) for that?Kyongkyoto
It is non-standard (as of now) but the url is: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Evanish
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Function.caller: Non-standard This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.Interline
@RocketHazmat callee.name will give empty string if function is anonymous.Com
it is important to note that arguments.callee is deprecated and unavailable in strict mode. see why here: #104098Procathedral
Function.caller doesn't work for most of ES6: it is a forbidden extension for strict mode functions, that, if defined, must throw when accessed. And ES6 modules are always in strict mode. Chrome's V8 implements this; only sloppy mode functions have caller. This is for security reasons.Lat
Anyone looking for a more modern solution that works in Typescript & frameworks like Angular too, use console.log((new Error).stack);Knitting
in my case it return null valueRasp
@ReinBaarsma this gives one big stringIndiscerptible
@RocketHazmat old post comment but thanks! Indeed, "arguments.callee.caller.name" will get the name, and this is a major help when maintaining an older site where a lot of "onclick" or "on-whatever()" events are attached to items that call the same handler! Often the original code only passes "this", which is good for deriving the object, but can NOT offer the event type! In newer browsers 'event' or at least 'window.event' is available, but there are exceptions! Now, when neither is available, I have a plan B, since the event type can be derived from the caller name! AWESOME!Autonomic
Thank you so much for your resarch. I am writing a "hyper-compatible" renderer, which is meant to be compatible with historic browsers like Internet Explorer and Netscape while also having modern features. Your comment has helped tremendously!Kathrinkathrine
Not work with calss constructor , any idea to get it work?Sensual
S
167

StackTrace

You can find the entire stack trace using browser specific code. The good thing is someone already made it; here is the project code on GitHub.

But not all the news is good:

  1. It is really slow to get the stack trace so be careful (read this for more).

  2. You will need to define function names for the stack trace to be legible. Because if you have code like this:

    var Klass = function kls() {
       this.Hello = function() { alert(printStackTrace().join('\n\n')); };
    }
    new Klass().Hello();
    

    Google Chrome will alert ... kls.Hello ( ... but most browsers will expect a function name just after the keyword function and will treat it as an anonymous function. An not even Chrome will be able to use the Klass name if you don't give the name kls to the function.

    And by the way, you can pass to the function printStackTrace the option {guess: true} but I didn't find any real improvement by doing that.

  3. Not all browsers give you the same information. That is, parameters, code column, etc.


Caller Function Name

By the way, if you only want the name of the caller function (in most browsers, but not IE) you can use:

arguments.callee.caller.name

But note that this name will be the one after the function keyword. I found no way (even on Google Chrome) to get more than that without getting the code of the whole function.


Caller Function Code

And summarizing the rest of the best answers (by Pablo Cabrera, nourdine, and Greg Hewgill). The only cross-browser and really safe thing you can use is:

arguments.callee.caller.toString();

Which will show the code of the caller function. Sadly, that is not enough for me, and that is why I give you tips for the StackTrace and the caller function Name (although they are not cross-browser).

Sublingual answered 24/9, 2010 at 16:38 Comment(3)
perhaps you should add Function.caller per @Greg's answerHaas
Function.caller wont work in strict mode, however.Optional
doesn't work in Chrome and Firefox, using Vue2Lactiferous
H
111

I usually use (new Error()).stack in Chrome. The nice thing is that this also gives you the line numbers where the caller called the function. The downside is that it limits the length of the stack to 10, which is why I came to this page in the first place.

(I'm using this to collect callstacks in a low-level constructor during execution, to view and debug later, so setting a breakpoint isn't of use since it will be hit thousands of times)

Harmonium answered 7/5, 2015 at 14:15 Comment(8)
Could you please add a little more description about the explanation you provide?Lu
This is the only thing I could get to work when 'use strict'; is in place. Gave me the info I needed -- thanks!Averment
Regarding the limit of stack length... you can change that with "Error.stackTraceLimit = Infinity".Gamma
(new Error("StackLog")).stack.split("\n") makes it nicer to read.Monde
new Error().stack.toString().match(/at \w+\.\w+/)[0].split('.')[1] to get the caller's name. I wrote a console.log method that didn't log in production.Optional
this is perfect! now that in browser's devtools and in node strict mode is uncancellable, this seems to be the only option. Thank you!Samhita
not to get alerted to "error", I used it as: (new Error()).stack.replace('Error', '')Samhita
I did not need 'use strict' and it works in the client. I did not test in node.Fernand
G
86

In both ES6 and Strict mode, use the following to get the Caller function

console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])

Please note that, the above line will throw an exception if there is no caller or no previous stack. Use accordingly.

To get callee (the current function name), use:

console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1]) 
Godsey answered 14/7, 2019 at 1:9 Comment(2)
object possibly undefined, so add an "?": .stack?Lauber
Perhaps this one should be the accepted answer now?Grandmotherly
A
82

I know you mentioned "in Javascript", but if the purpose is debugging, I think it's easier to just use your browser's developer tools. This is how it looks in Chrome: enter image description here Just drop the debugger where you want to investigate the stack.

Aftereffect answered 3/2, 2015 at 0:28 Comment(2)
This is an old question... but this is definitely the modern most valid way of doing this today.Shirlyshiroma
best way to debug javascript in browserPectinate
R
68

If you are not going to run it in IE < 11 then console.trace() would suit.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4
Raynard answered 18/1, 2016 at 10:58 Comment(1)
This can't be used if you want just name of Callee or Caller function. This function executes output directly to console and output can't be handled in code. Simply saying, that function doesn't have return type.Lactiferous
A
54

You can get the full stacktrace:

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

Until caller is null.

Note: it cause an infinite loop on recursive functions.

Atoll answered 28/10, 2010 at 22:33 Comment(1)
it will stop also if one of the functions is async, not reliable.Waiter
H
52

To recap (and make it clearer) ...

this code:

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

is equivalent to this:

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

Clearly the first bit is more portable, since you can change the name of the function, say from "Hello" to "Ciao", and still get the whole thing to work.

In the latter, in case you decide to refactor the name of the invoked function (Hello), you would have to change all its occurrences :(

Holmun answered 6/4, 2009 at 13:47 Comment(2)
arguments.callee.caller always null on Chrome 25.0.1364.5 devCari
this answer does not cover the stict mode when "on"Lauber
N
36

I would do this:

function Hello() {
  console.trace();
}
Nelson answered 16/11, 2017 at 22:40 Comment(3)
This is working great! should by accepted as the right answer, as other ways are old \ don't work anymoreLambrecht
@inorganik, Hello, can you please explain what new or different in your answer in comparison with this one https://mcmap.net/q/53115/-how-do-you-find-out-the-caller-function-in-javascript ?Raynard
@Raynard it's good to have more good answers )Cycad
L
24

You can use Function.Caller to get the calling function. The old method using argument.caller is considered obsolete.

The following code illustrates its use:

function Hello() { return Hello.caller;}

Hello2 = function NamedFunc() { return NamedFunc.caller; };

function main()
{
   Hello();  //both return main()
   Hello2();
}

Notes about obsolete argument.caller: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Be aware Function.caller is non-standard: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

Live answered 6/6, 2015 at 21:1 Comment(4)
This is the right answer these days. You can't do arguments.caller.callee stuff anymore. Wish we could get this moved to the top since all the other stuff is outdated now.Sacken
Seems like this is not possible in strict mode? Cannot access caller property of a strict mode functionHaas
Function.caller didn't work for me in strict mode either. Also, according to MDN, function.caller is non-standard and shouldn't be used in production. It might work for debugging, though.Falsetto
I had no problem with non-standard if it worked in Node, but it is simply not allowed in strict mode (I tested on node 6.10). Same applies for 'arguments'. I get errror message: '''caller' and 'arguments' are restricted function properties and cannot be accessed in this context."Gamma
B
23

heystewart's answer and JiarongWu's answer both mentioned that the Error object has access to the stack.

Here's an example:

function main() {
  Hello();
}

function Hello() {
  try {
    throw new Error();
  } catch  (err) {
    let stack = err.stack;
    // N.B. stack === "Error\n  at Hello ...\n  at main ... \n...."
    let m = stack.match(/.*?Hello.*?\n(.*?)\n/);
    if (m) {
      let caller_name = m[1];
      console.log("Caller is:", caller_name);
    }
  }
}

main();

Different browsers shows the stack in different string formats:

Safari  : Caller is: main@https://stacksnippets.net/js:14:8
Firefox : Caller is: main@https://stacksnippets.net/js:14:3
Chrome  : Caller is:     at main (https://stacksnippets.net/js:14:3)
IE Edge : Caller is:    at main (https://stacksnippets.net/js:14:3)
IE      : Caller is:    at main (https://stacksnippets.net/js:14:3)

Most browsers will set the stack with var stack = (new Error()).stack. In Internet Explorer the stack will be undefined - you have to throw a real exception to retrieve the stack.

Conclusion: It's possible to determine "main" is the caller to "Hello" using the stack in the Error object. In fact it will work in cases where the callee / caller approach doesn't work. It will also show you context, i.e. source file and line number. However effort is required to make the solution cross platform.

Bizet answered 13/7, 2017 at 5:36 Comment(0)
B
22

Looks like this is quite a solved question but I recently found out that callee is not allowed in 'strict mode' so for my own use I wrote a class that will get the path from where it is called. It's part of a small helper lib and if you want to use the code standalone change the offset used to return the stack trace of the caller (use 1 instead of 2)

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}
Bandwagon answered 4/3, 2014 at 7:14 Comment(5)
Doesn't work for me with function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a() in the console (haven't tried in a file), but seems to have a reasonable idea. Should be upvoted anyway for visibility.Charley
The idea is great. I'm parsing differently but in nw.js apps, this is really the only idea that gives what i'm looking for.Backboard
Please provide an example of how to call this function.Pizor
Throw .. catch is unnecessary. It's possible to get stack by let stack =new Error().stack.Vicinal
Seems my previous comment is wrong and thow ... catch required to get stack in IE browser according to github.com/stacktracejs/stacktrace.js/blob/master/… .Vicinal
C
21
function Hello() {
    alert(Hello.caller);
}
Copalite answered 11/11, 2008 at 10:56 Comment(5)
And just for the function name use Hello.caller.nameIsocline
same as arguments.callee.caller.toString()Hellhole
This should be the correct answer, at least for 2016Bookish
This is not on a standards track, but will work as of ECMAScript 5.Crinkumcrankum
@Daniel: no, it shouldn't. See developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Conquest
H
19

It's safer to use *arguments.callee.caller since arguments.caller is deprecated...

Hild answered 11/11, 2008 at 9:50 Comment(2)
arguments.callee is also deprecated in ES5, and removed in strict mode.Marcasite
Is there an alternative? Edit: arguments.callee was a bad solution to a problem that has now been better solved developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Vermiform
I
18

2018 Update

caller is forbidden in strict mode. Here is an alternative using the (non-standard) Error stack.

The following function seems to do the job in Firefox 52 and Chrome 61-71 though its implementation makes a lot of assumptions about the logging format of the two browsers and should be used with caution, given that it throws an exception and possibly executes two regex matchings before being done.

'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;

function fnName(str) {
  const regexResult = fnNameMatcher.exec(str);
  return regexResult[1] || regexResult[2];
}

function log(...messages) {
  const logLines = (new Error().stack).split('\n');
  const callerName = fnName(logLines[1]);

  if (callerName !== null) {
    if (callerName !== 'log') {
      console.log(callerName, 'called log with:', ...messages);
    } else {
      console.log(fnName(logLines[2]), 'called log with:', ...messages);
    }
  } else {
    console.log(...messages);
  }
}

function foo() {
  log('hi', 'there');
}

(function main() {
  foo();
}());
Impulsion answered 26/2, 2018 at 10:2 Comment(3)
That's incredible, and also horrifying.Padauk
I got "foo called with: hi there", but foo wasn't called with "hi there", log was called with "hi there"Enallage
Right, there was a "misplaced modifier" in the grammar of the error message. It meant to say "log was called from function f, it wanted the message X printed" but in as a succinct way as possible.Impulsion
N
12

Just console log your error stack. You can then know how are you being called

const hello = () => {
  console.log(new Error('I was called').stack)
}

const sello = () => {
  hello()
}

sello()
Nausea answered 14/3, 2018 at 9:49 Comment(0)
C
11

Try accessing this:

arguments.callee.caller.name
Chuckle answered 11/11, 2008 at 10:19 Comment(1)
This has been deprecated for many years.Conquest
C
8

I wanted to add my fiddle here for this:

http://jsfiddle.net/bladnman/EhUm3/

I tested this is chrome, safari and IE (10 and 8). Works fine. There is only 1 function that matters, so if you get scared by the big fiddle, read below.

Note: There is a fair amount of my own "boilerplate" in this fiddle. You can remove all of that and use split's if you like. It's just an ultra-safe" set of functions I've come to rely on.

There is also a "JSFiddle" template in there that I use for many fiddles to simply quick fiddling.

Cruse answered 7/9, 2012 at 15:32 Comment(1)
I wonder if you could add the "helpers" as extensions for the prototype in some cases, for example: String.prototype.trim = trim;Bibbs
N
6

If you just want the function name and not the code, and want a browser-independent solution, use the following:

var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];

Note that the above will return an error if there is no caller function as there is no [1] element in the array. To work around, use the below:

var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);
Nursery answered 15/3, 2012 at 3:46 Comment(2)
This has been deprecated for many years.Conquest
This is not what ternary operators are for, you're recalculating everything three times! This is what variables are for,Hixon
C
6

Using Error.stack property is the general solution for pure javascript for getting a caller function name (or full callstack). But it can be resource intensive in case of long stacks or frequent calls, because you operate with string object by slow trim, split or match methods.

The better solution is accessing to the stack's array of CallSite items directly with prepareStackTrace:

function getCallerName() {
  // Get stack array
  const orig = Error.prepareStackTrace;
  Error.prepareStackTrace = (error, stack) => stack;
  const { stack } = new Error();
  Error.prepareStackTrace = orig;
  
  const caller = stack[2];
  return caller ? caller.getFunctionName() : undefined;
}

It works great with classes, arrow and async functions etc., for instance:

function hello() {
  console.log(getCallerName());
}

class A {
  constructor() {
    console.log(getCallerName());
  }
  
  hello() {
    console.log(getCallerName());
  }
}

function main() {
  hello(); // Prints: main
  
  const a = new A(); // Prints: main
  a.hello(); // Prints: main
}

main();
Carbonization answered 17/4, 2023 at 17:12 Comment(1)
Do note this is V8 specific, so only available in Chromium derived browsersSignorelli
T
5

Here, everything but the functionname is stripped from caller.toString(), with RegExp.

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Show the callers name</title><!-- This validates as html5! -->
<script>
main();
function main() { Hello(); }
function Hello(){
  var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,'');
  name = name.replace(/\s/g,'');
  if ( typeof window[name] !== 'function' )
    alert ("sorry, the type of "+name+" is "+ typeof window[name]);
  else
    alert ("The name of the "+typeof window[name]+" that called is "+name);
}
</script>
Thigpen answered 12/9, 2012 at 8:35 Comment(1)
this is still returning the entire method declarationWeswesa
B
5

Just want to let you know that on PhoneGap/Android the name doesnt seem to be working. But arguments.callee.caller.toString() will do the trick.

Bukovina answered 8/4, 2014 at 17:59 Comment(0)
I
5

Note you can't use Function.caller in Node.js, use caller-id package instead. For example:

var callerId = require('caller-id');

function foo() {
    bar();
}
function bar() {
    var caller = callerId.getData();
    /*
    caller = {
        typeName: 'Object',
        functionName: 'foo',
        filePath: '/path/of/this/file.js',
        lineNumber: 5,
        topLevelFlag: true,
        nativeFlag: false,
        evalFlag: false
    }
    */
}
Inferential answered 24/2, 2020 at 6:55 Comment(0)
C
4

here is a function to get full stacktrace:

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}
Calcine answered 13/4, 2016 at 11:12 Comment(0)
T
3

Works great for me, and you can chose how much you want to go back in the functions:

function getCaller(functionBack= 0) {
    const back = functionBack * 2;
    const stack = new Error().stack.split('at ');
    const stackIndex = stack[3 + back].includes('C:') ? (3 + back) : (4 + back);
    const isAsync = stack[stackIndex].includes('async');
    let result;
    if (isAsync)
      result = stack[stackIndex].split(' ')[1].split(' ')[0];
    else
      result = stack[stackIndex].split(' ')[0];
    return result;
}
Tureen answered 6/12, 2020 at 13:34 Comment(0)
C
3

I could use these in 2021 and get the stack which starts from the caller function :

1. console.trace();
2. console.log((new Error).stack)

// do the same as #2 just with better view
3. console.log((new Error).stack.split("\n")) 
Coleman answered 4/11, 2021 at 10:3 Comment(0)
V
2

Try the following code:

function getStackTrace(){
  var f = arguments.callee;
  var ret = [];
  var item = {};
  var iter = 0;

  while ( f = f.caller ){
      // Initialize
    item = {
      name: f.name || null,
      args: [], // Empty array = no arguments passed
      callback: f
    };

      // Function arguments
    if ( f.arguments ){
      for ( iter = 0; iter<f.arguments.length; iter++ ){
        item.args[iter] = f.arguments[iter];
      }
    } else {
      item.args = null; // null = argument listing not supported
    }

    ret.push( item );
  }
  return ret;
}

Worked for me in Firefox-21 and Chromium-25.

Varsity answered 22/6, 2013 at 20:33 Comment(2)
Try this for recursive functions.Cassiani
arguments.callee has been deprecated for many years.Conquest
B
1

Another way around this problem is to simply pass the name of the calling function as a parameter.

For example:

function reformatString(string, callerName) {

    if (callerName === "uid") {
        string = string.toUpperCase();
    }

    return string;
}

Now, you could call the function like this:

function uid(){
    var myString = "apples";

    reformatString(myString, function.name);
}

My example uses a hard coded check of the function name, but you could easily use a switch statement or some other logic to do what you want there.

Bar answered 4/3, 2016 at 15:29 Comment(1)
I believe this also solves cross browser compatibility issues, for the most part. But please test this before assuming it to be true! (starts to sweat)Bar
K
1

As far as I know, we have 2 way for this from given sources like this-

  1. arguments.caller

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
    
  2. Function.caller

    function myFunc()
    {
       if (myFunc.caller == null) {
          return 'The function was called from the top!';
       }
       else
       {
          return 'This function\'s caller was ' + myFunc.caller;
        }
    }
    

Think u have your answer :).

Kunstlied answered 28/3, 2016 at 5:34 Comment(1)
This has been deprecated for many years, and Function.caller doesn't work in strict mode.Conquest
B
1

I'm attempting to address both the question and the current bounty with this question.

The bounty requires that the caller be obtained in strict mode, and the only way I can see this done is by referring to a function declared outside of strict mode.

For example, the following is non-standard but has been tested with previous (29/03/2016) and current (1st August 2018) versions of Chrome, Edge and Firefox.

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

'use strict';
function main()
{
   // Original question:
   Hello();
   // Bounty question:
   (function() { console.log('Anonymous function called by ' + caller().name); })();
}

function Hello()
{
   // How do you find out the caller function is 'main'?
   console.log('Hello called by ' + caller().name);
}

main();
Bibbs answered 29/3, 2016 at 6:40 Comment(1)
Nice hack, but won't work for ES5 modules, which are entirely in strict mode.Conquest
M
1

Why all of the solutions above look like a rocket science. Meanwhile, it should not be more complicated than this snippet. All credits to this guy

How do you find out the caller function in JavaScript?

var stackTrace = function() {

    var calls = [];
    var caller = arguments.callee.caller;

    for (var k = 0; k < 10; k++) {
        if (caller) {
            calls.push(caller);
            caller = caller.caller;
        }
    }

    return calls;
};

// when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content
// [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)]
Millhon answered 7/2, 2017 at 17:52 Comment(1)
This is what i get on using this: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them. Any ideas how to work this in strict mode?Sesterce
K
1

I think the following code piece may be helpful:

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

Execute the code:

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

function fnBsnCallStack1() {
    fnPureLog('Stock Count', 100)
}

function fnBsnCallStack2() {
    fnBsnCallStack1()
}

fnBsnCallStack2();

The log looks like this:

Call Stack:
    at window.fnPureLog (<anonymous>:8:27)
    at fnBsnCallStack1 (<anonymous>:13:5)
    at fnBsnCallStack2 (<anonymous>:17:5)
    at <anonymous>:20:1 
Stock Count: 100
Keven answered 28/4, 2017 at 7:27 Comment(1)
This is HUGELY HELPFUL because (on Chrome, anyway) dumping the new Error() object unmodified shows the SOURCE file/line info (such as the TypeScript info). AFTER the replace, though, you get the ACTUAL transpiled JavaScript info. I have no idea why just replacing a string does this, but it's a neat accident. Also, with the transpiled code, it shows the actual URL that the code came from, rather than just the module name. Extracting the third line of the output in either case can produce the caller's location in either the original source code, or the transpiled JavaScript.Pustule
D
1

As none of previous answers works like what I was looking for(getting just the last function caller not a function as a string or callstack) I post my solution here for those who are like me and hope this will work for them:

function getCallerName(func)
{
  if (!func) return "anonymous";
  let caller = func.caller;
  if (!caller) return "anonymous";
  caller = caller.toString();
  if (!caller.trim().startsWith("function")) return "anonymous";
  return caller.substring(0, caller.indexOf("(")).replace("function","");
}


//  Example of how to use "getCallerName" function

function Hello(){
console.log("ex1  =>  " + getCallerName(Hello));
}

function Main(){
Hello();

// another example
console.log("ex3  =>  " + getCallerName(Main));
}

Main();
Diastole answered 22/10, 2018 at 9:19 Comment(3)
caller doesn't work in strict mode.Conquest
@DanDascalescu, I don't see any request for strict mode in the question!Diastole
Casting function to a string to get its name can be very slow.Sporades
U
1

You can use debugger; in function . open inespect elements and watch call stack;

Undetermined answered 29/1, 2022 at 11:33 Comment(0)
L
1

With Strict Mode On/Off (JavaScript & TypeScript), if (!) the caller exist you can try this one

console.log(`caller:${(new Error()).stack?.split('\n')[2].trim().split(' ')[1]}`)
Lauber answered 17/6, 2022 at 8:55 Comment(0)
M
0

If you really need the functionality for some reason and want it to be cross-browser compatible and not worry for strict stuff and be forward compatible then pass a this reference:

function main()
{
   Hello(this);
}

function Hello(caller)
{
    // caller will be the object that called Hello. boom like that... 
    // you can add an undefined check code if the function Hello 
    // will be called without parameters from somewhere else
}
Mame answered 3/11, 2015 at 1:22 Comment(0)
I
0
function main()
{
   Hello();
}

function Hello()
{
  new Error().stack
}
Issuable answered 29/10, 2021 at 12:48 Comment(1)
Your answer could be improved with additional supporting information. Please "edit" to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center: stackoverflow.com/help/how-to-answerSteverson
E
-1

paste the following piece of code at the start of your program:

window.__defineGetter__("currentStack",function(){
var rv=[];
var base_element=arguments.callee.caller;
while (base_element){
rv.push(base_element);
base_element=base_element.caller};
return rv
});

you can now access the currentStack global "variable" (if you can call it that) from within any function, and it will be set to an array, where the first item is the current function, accessing the property, the second item is the function that called it, the third item is the function that called the second one, ...

Example:

f1=function(){
f2()};
f2=function(){
f3()};
f3=function(){
console.log(currentStack)}
f1(); //expected output: [function f3(), function f2(), function f1()] 
//exact formatting is browser specific

NOTE: DO NOT use strict mode when using this. It will lead to an error. Accessing currentStack only works in a synchronous, non-generator, non-arrow function. In any other function, or at module level, currentStack is an empty Array ([]). At the modern-day, it will also stop walking up the stack when an recursive call is made.(Atleast in Firefox, i didn't check any other browser). Some time ago, it would have entered an infinite loop, blocking the calling thread forever

Ermaermanno answered 24/3, 2023 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.