Frage

function main()
{
   Hello();
}

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

Gibt es eine Möglichkeit den Call-Stack, um herauszufinden?

War es hilfreich?

Lösung

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

Beachten Sie, dass diese Funktion Nicht-Standard , von Function.caller :

  

Nicht-Standard
  Diese Funktion ist nicht-Standard und ist nicht auf eine Spur Standards. Verwenden Sie es nicht auf die Produktion Websites, um den Web konfrontiert: Es wird nicht für jeden Benutzer arbeiten. Es gibt auch große Inkompatibilitäten zwischen Implementierungen sein kann und das Verhalten in der Zukunft ändern kann.


Im Folgenden ist die alte Antwort aus dem Jahr 2008, die nicht mehr in der modernen Javascript unterstützt:

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

Andere Tipps

Stacktrace

Sie können den gesamten Stack-Trace finden spezifischen Code mit Browser. Die gute Sache ist jemand schon gemacht ; hier ist der Projektcode auf GitHub .

Aber nicht alle Nachrichten ist gut:

  1. Es ist wirklich langsam das Stack-Trace zu erhalten, so vorsichtig sein (lesen Sie diese mehr).

  2. Sie müssen Funktionsnamen definieren, für den Stack-Trace lesbar zu sein. Denn wenn Sie Code wie folgt:

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

    Google Chrome warnt ... kls.Hello ( ... aber die meisten Browser einen Funktionsnamen nur nach dem Schlüsselwort function erwarten und es als eine anonyme Funktion behandeln. Ein nicht einmal Chrome wird die Klass Namen verwenden können, wenn Sie den Namen kls auf die Funktion nicht geben.

    Und übrigens, können Sie an die Funktion übergeben print die Option {guess: true} aber ich habe keine wirkliche Verbesserung finden, indem das zu tun.

  3. Nicht alle Browser gibt Ihnen die gleichen Informationen. Das heißt, Parameter, Codespalte, etc.


Caller Funktion Name

By the way, wenn Sie nur den Namen des Anrufers Funktion soll (in den meisten Browsern, aber nicht IE) können Sie:

arguments.callee.caller.name

Aber beachten Sie, dass dieser Name der einer nach dem function Schlüsselwort sein wird. Ich fand keinen Weg (auch auf Google Chrome), um mehr als das zu bekommen, ohne den Code der gesamten Funktion zu bekommen.


Caller Funktionscode

Und Zusammenfassung der Rest der besten Antworten (von Pablo Cabrera, Nourdine und Greg Hewgill). Der einzige Cross-Browser und wirklich sicher, was Sie verwenden können, ist:

arguments.callee.caller.toString();

, die den Code zeigt der CLIP-Funktion. Leider, das ist nicht genug für mich, und das ist, warum ich Ihnen Tipps für die Stacktrace geben und die CLIP-Funktion Namen (obwohl sie nicht Cross-Browser sind).

Zur Erinnerung (und macht es klarer) ...

Mit diesem Code:

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

entspricht dies:

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

Klar das erste Bit ist mehr tragbar, da Sie den Namen der Funktion ändern kann, etwa von „Hallo“ zu „Ciao“, und immer noch die ganze Sache zu arbeiten.

Im letzteren, falls Sie sich entscheiden, den Namen der aufgerufenen Funktion (Hallo), Refactoring, Sie müßten alle ihre Vorkommen ändern :(

Sie können den vollständigen Stacktrace erhalten:

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

Bis Anrufer null ist.

Hinweis: es eine Endlosschleife auf rekursive Funktionen verursacht

.

Ich weiß, Sie erwähnen „in Javascript“, aber wenn der Zweck Debuggen ist, ich denke, es ist einfacher, nur der Browser Entwickler-Tools zu verwenden. Dies ist, wie es aussieht, ist in Chrome: image description treten Sie hier Legen Sie einfach den Debugger, wo Sie den Stapel untersuchen möchten.

Normalerweise verwende ich (new Error()).stack in Chrome. Das Schöne daran ist, dass dies gibt Ihnen auch die Zeilennummern, wo der Anrufer die Funktion aufgerufen. Der Nachteil ist, dass es die Länge des Stapels auf 10 begrenzt, weshalb ich auf dieser Seite an erster Stelle kam.

(Ich verwende diese während der Ausführung in einem Callstacks Low-Level-Konstruktor zu sammeln, zu einem späteren Zeitpunkt zu ansehen und zu debuggen, so einen Haltepunkts Einstellung ist nicht von Nutzen, da wird es tausende Male getroffen werden)

Wenn Sie vorhaben, es nicht in IE laufen <11 dann console.trace () passen würde.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4

Sie können Function.Caller verwenden, um die Aufruffunktion zu erhalten. Die alte Methode argument.caller Verwendung gilt als veraltet.

Der folgende Code zeigt die Verwendung:

function Hello() { return Hello.caller;}

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

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

Hinweise zu veralteten argument.caller: https: // developer. mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Beachten Sie Function.caller ist Nicht-Standard: https: / /developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

function Hello() {
    alert(Hello.caller);
}

Es ist sicherer *arguments.callee.caller zu verwenden, da arguments.caller ist veraltet ...

Sieht aus wie diese ziemlich gelöst Frage, aber ich vor kurzem herausgefunden, dass Angerufenen werden in ‚Strict-Modus‘ nicht erlaubt so für meinen eigenen Gebrauch ich eine Klasse geschrieben, die den Weg von wo es heißt bekommen. Es ist Teil eines kleinen Helfer lib und wenn Sie den Code Standalone verwenden mögen ändert die Offsets, den Stack-Trace des Anrufers (Verwendung 1 statt 2)

zurück
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('.');
  };
}

Ich würde dies tun:

function Hello() {
  console.trace();
}
Versuchen

Zugriff auf diese:

arguments.callee.caller.name

Just Konsolprotokoll Ihre Fehler-Stack. Anschließend können Sie wissen, wie Sie genannt werden

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

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

sello()

Ich wollte meine Geige hier für diesen hinzuzufügen:

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

Getestet habe ich diese ist Chrome, Safari und IE (10 und 8). Funktioniert gut. Es gibt nur 1 Funktion, worauf es ankommt, wenn Sie also durch die große Geige Angst bekommen, lesen Sie unten.

Hinweis: Es gibt eine ganze Menge meiner eigenen „vorformulierten“ in dieser Geige. Sie können alle, dass entfernen und Split, wenn Sie möchten. Es ist nur eine ultra-sichere“Reihe von Funktionen, die ich gekommen bin zu vertrauen.

Es gibt auch eine „JSFiddle“ -Vorlage in dort, dass ich einfach schnell Hantieren für viele Geigen verwenden.

2018-Update

caller im Strict-Modus verboten . Hier ist eine Alternative, die (Nicht-Standard) unter Verwendung von Error Stapel .

Die folgende Funktion scheint die Arbeit in Firefox 52 und Chrome 61-71 zu tun, obwohl seine Umsetzung eine Menge Annahmen über das Protokollformat der beiden Browser macht und soll mit Vorsicht angewandt werden, da es eine Ausnahme auslöst und möglicherweise führt zwei regex passende zuvor getan wird.

'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 with:', ...messages);
    } else {
      console.log(fnName(logLines[2]), 'called with:', ...messages);
    }
  } else {
    console.log(...messages);
  }
}

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

(function main() {
  foo();
}());

Wenn Sie nur den Funktionsnamen möchten und nicht der Code, und wollen einen Browser-unabhängige Lösung, verwenden Sie die folgende:

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

Beachten Sie, dass die oben einen Fehler zurück, wenn es keine CLIP-Funktion ist, da es kein [1] Element im Array. Zum Umgehen Verwenden Sie die folgenden:

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

Ich will nur Sie wissen lassen, dass auf PhoneGap / Android die name scheint nicht zu funktionieren. Aber arguments.callee.caller.toString() den Trick.

Hier ist alles, aber die functionname aus caller.toString() gestrippt, mit 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>

Hier ist eine Funktion, get full stacktrace :

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}

heystewart Antwort und JiarongWu Antwort beide erwähnt, dass die Error Objekt Zugang zum stack hat.

Hier ist ein Beispiel:

function main() {
  Hello();
}

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

main();

Verschiedene Browser zeigt den Stapel in verschiedenen String-Formate:

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)

Die meisten Browser den Stapel mit var stack = (new Error()).stack gesetzt. Im Internet Explorer wird der Stapel nicht definiert - Sie haben eine echte Ausnahme werfen, um den Stapel abrufen

.

Fazit: Es ist möglich, „main“ ist der Anrufer zu „Hallo“ mit dem stack im Error Objekt zu bestimmen. In der Tat wird es in Fällen arbeiten, wo der callee / caller Ansatz funktioniert nicht. Es zeigt Ihnen auch Kontext, das heißt Quelldatei und Zeilennummer. Allerdings Anstrengungen erforderlich, um die Lösung Cross-Plattform zu machen.

Versuchen Sie, den folgenden 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;
}

Für mich arbeitet in Firefox-21 und Chromium-25.

Eine andere Möglichkeit, um dieses Problem besteht darin, einfach den Namen des anrufenden Funktion als Parameter übergeben.

Zum Beispiel:

function reformatString(string, callerName) {

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

    return string;
}

Nun könnten Sie die Funktion wie folgt aufrufen:

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

    reformatString(myString, function.name);
}

Mein Beispiel verwendet eine hartcodierte Überprüfung der Funktionsnamen, aber Sie einfach eine switch-Anweisung oder eine andere Logik verwenden könnten zu tun, was Sie wollen es.

Soweit ich weiß, haben wir 2 Art und Weise für diesen aus bestimmten Quellen wie diese -

  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;
        }
    }
    

Denken Sie u haben Ihre Antwort.)

Warum alle Lösungen oben aussehen wie eine Rakete Wissenschaft. Inzwischen sollte es nicht komplizierter sein als dieser Schnipsel. Alle Gutschriften zu diesem Typ

Wie finden Sie heraus, die CLIP-Funktion 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)]

ich sowohl die Frage und die aktuelle Prämie mit dieser Frage zu befassen bin versucht.

Die Prämie setzt voraus, dass der Anrufer in erhalten werden strenge Modus, und die einzige Art, wie ich dies auf eine Funktion getan sehen kann unter Bezugnahme erklärt außerhalb von Strict-Modus.

Zum Beispiel ist das Folgende nicht-Standard hat aber mit früheren (29/03/2016) und Strom (1. August 2018) Versionen von Chrome, Kanten- und Firefox getestet.

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

Wenn Sie wirklich die Funktionalität aus irgendeinem Grund brauchen und wollen es Cross-Browser-kompatibel und nicht für strenge Sachen Sorge zu sein und nach vorne dann eine diesen Verweis übergeben kompatibel sein:

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
}

Ich denke, das folgende Code Stück hilfreich sein kann:

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

Führen Sie den Code ein:

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

Das Protokoll sieht wie folgt aus:

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

Da keiner der bisherigen Antworten funktioniert wie das, was ich gesucht habe (nur die letzte Funktion Anrufer nicht eine Funktion als String oder Aufrufliste bekommen) ich meine Lösung hier posten für diejenigen, die wie ich sind und hoffen, dass dies für sie arbeiten wird:

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top