How do you find out the caller function in JavaScr

2018-12-31 02:55发布

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 at all?

29条回答
与风俱净
2楼-- · 2018-12-31 03:28

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

查看更多
只靠听说
3楼-- · 2018-12-31 03:30

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
查看更多
刘海飞了
4楼-- · 2018-12-31 03:30

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('.');
  };
}
查看更多
ら面具成の殇う
5楼-- · 2018-12-31 03:30

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>
查看更多
初与友歌
6楼-- · 2018-12-31 03:31

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

查看更多
妖精总统
7楼-- · 2018-12-31 03:32

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.

查看更多
登录 后发表回答