How do you find out the caller function in JavaScript?

前端 未结 30 1500
粉色の甜心
粉色の甜心 2020-11-21 17:46
function main()
{
   Hello();
}

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

Is there a way to find out the call

相关标签:
30条回答
  • 2020-11-21 17:55

    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('.');
      };
    }
    
    0 讨论(0)
  • 2020-11-21 17:55

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

    0 讨论(0)
  • 2020-11-21 17:56

    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
    
    0 讨论(0)
  • 2020-11-21 17:57

    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.

    0 讨论(0)
  • 2020-11-21 17:58

    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 :(

    0 讨论(0)
  • 2020-11-21 17:58

    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]);
    
    0 讨论(0)
提交回复
热议问题