Wie finden Sie die Aufruferfunktion in JavaScript heraus?

866
function main()
{
   Hello();
}

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

Gibt es eine Möglichkeit, den Aufrufstapel herauszufinden?

Ray Lu
quelle
63
Ich hoffe, dies soll Ihnen nur beim Debuggen helfen. Unterschiedliches Verhalten basierend auf dem Anrufer ist eine schlechte Idee.
ABl.
Wann wäre dies zum Debuggen nützlich?
Anderson Green
33
@AndersonGreen, wenn Sie beispielsweise eine Standardmethode zum Rendern von Vorlagen haben und sehen, dass diese zweimal aufgerufen wird. Anstatt 1000 LoC zu durchkämmen oder mühsam mit dem Debugger durchzugehen, können Sie nur sehen, was der Stapel zu der Zeit war.
Tkone
28
Um die Stapelverfolgung anzuzeigen, verwenden Sie console.trace () für Chrome.
Ich
5
Warum ist das eine schlechte Idee?
Jacob Schneider

Antworten:

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

Beachten Sie, dass diese Funktion nicht-Standard , aus Function.caller:

Nicht standardisiert
Diese Funktion ist nicht standardisiert und befindet sich nicht auf einer Standardspur. Verwenden Sie es nicht auf Produktionsstandorten mit Blick auf das Web: Es funktioniert nicht für jeden Benutzer. Es kann auch große Inkompatibilitäten zwischen Implementierungen geben, und das Verhalten kann sich in Zukunft ändern.


Das Folgende ist die alte Antwort aus dem Jahr 2008, die im modernen Javascript nicht mehr unterstützt wird:

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}
Greg Hewgill
quelle
254
arguments.callee.caller.nameerhält den Namen der Funktion.
Rocket Hazmat
137
"Auf die Eigenschaften" Aufrufer "," Angerufene "und" Argumente "kann möglicherweise nicht über Funktionen im strengen Modus oder auf die Argumente Objekte für Aufrufe zugegriffen werden" - sie sind in ES5 veraltet und werden im strengen Modus entfernt.
ThatGuy
12
Es funktioniert nur, wenn Sie nicht den strengen Modus verwenden. Das Entfernen 'use strict';könnte also helfen.
pvorb
23
argumentsAuf CAN kann innerhalb einer Funktion im strengen Modus zugegriffen werden. Es wäre dumm, dies zu verwerfen. nur nicht von function.arguments von außen. Wenn Sie ein benanntes Argument haben, verfolgt die Argumentform [i] keine Änderungen, die Sie an der benannten Version innerhalb der Funktion vorgenommen haben.
rvr_jon
41
Diese Methode ist veraltet, seit dieser Beitrag im Jahr 2011 aufgeführt wurde. Die bevorzugte Methode ist jetzt Function.caller (Stand 2015).
Greg
152

StackTrace

Sie können den gesamten Stack-Trace mit browserspezifischem Code finden. Das Gute ist, dass jemand es bereits geschafft hat ; Hier ist der Projektcode auf GitHub .

Aber nicht alle Nachrichten sind gut:

  1. Es ist sehr langsam, den Stack-Trace zu erhalten. Seien Sie also vorsichtig (lesen Sie dies für weitere Informationen).

  2. Sie müssen Funktionsnamen definieren, damit die Stapelverfolgung lesbar ist. Denn wenn Sie Code wie diesen haben:

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

    Google Chrome benachrichtigt Sie, ... kls.Hello ( ...aber die meisten Browser erwarten einen Funktionsnamen direkt nach dem Keyword functionund behandeln ihn als anonyme Funktion. Ein nicht einmal Chrome kann den KlassNamen verwenden, wenn Sie den Namen nicht angebenkls der Funktion .

    Übrigens können Sie die Option an die Funktion printStackTrace übergeben, {guess: true}aber ich habe dadurch keine wirkliche Verbesserung festgestellt .

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


Name der Anruferfunktion

Übrigens, wenn Sie nur den Namen der Anruferfunktion (in den meisten Browsern, aber nicht im Internet Explorer) möchten, können Sie Folgendes verwenden:

arguments.callee.caller.name

Beachten Sie jedoch, dass dieser Name nach dem functionSchlüsselwort steht. Ich habe keine Möglichkeit gefunden (auch nicht bei Google Chrome), mehr zu erreichen, ohne den Code der gesamten Funktion zu erhalten.


Funktionscode des Anrufers

Und die restlichen besten Antworten zusammenfassen (von Pablo Cabrera, Nourdine und Greg Hewgill). Die einzige browserübergreifende und wirklich sichere Sache, die Sie verwenden können, ist:

arguments.callee.caller.toString();

Welches zeigt den Code der Anruferfunktion. Leider reicht mir das nicht aus, und deshalb gebe ich Ihnen Tipps für die StackTrace und die Aufruferfunktion Name (obwohl sie nicht browserübergreifend sind).

Mariano Desanze
quelle
1
Vielleicht sollten Sie Function.callerper @ Gregs Antwort
Zach Lysobey
Function.callerfunktioniert jedoch nicht im strengen Modus.
Rickard Elimää
54

Ich weiß, dass Sie "in Javascript" erwähnt haben, aber wenn der Zweck das Debuggen ist, ist es meiner Meinung nach einfacher, nur die Entwicklertools Ihres Browsers zu verwenden. So sieht es in Chrome aus: Geben Sie hier die Bildbeschreibung ein Legen Sie einfach den Debugger dort ab, wo Sie den Stapel untersuchen möchten.

Phil
quelle
3
Dies ist eine alte Frage ... aber dies ist definitiv die modernste Methode, dies heute zu tun.
Markstewie
53

Um es noch einmal zusammenzufassen (und klarer zu machen) ...

dieser Code:

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

ist gleichbedeutend damit:

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

Das erste Bit ist eindeutig portabler, da Sie den Namen der Funktion ändern können, beispielsweise von "Hallo" in "Ciao", und trotzdem das Ganze zum Laufen bringen können.

In letzterem Fall müssten Sie alle Vorkommen ändern, wenn Sie den Namen der aufgerufenen Funktion (Hallo) umgestalten möchten :(

Nourdine
quelle
7
Argumente.callee.caller immer null auf Chrome 25.0.1364.5 dev
Kokizzu
53

Sie können die vollständige Stapelverfolgung erhalten:

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

Bis der Anrufer ist null.

Hinweis: Es verursacht eine Endlosschleife für rekursive Funktionen.

ale5000
quelle
2
Entschuldigen Sie die späte Antwort, aber ich habe Ihren Kommentar noch nicht gesehen. Nur für den Rekursionsfall funktioniert es nicht, in anderen Fällen sollte es funktionieren.
Ale5000
45

Ich benutze normalerweise (new Error()).stack in Chrome. Das Schöne ist, dass Sie dadurch auch die Zeilennummern erhalten, unter denen der Anrufer die Funktion aufgerufen hat. Der Nachteil ist, dass es die Länge des Stapels auf 10 begrenzt, weshalb ich überhaupt auf diese Seite gekommen bin.

(Ich verwende dies, um Callstacks in einem Konstruktor auf niedriger Ebene während der Ausführung zu sammeln, um sie später anzuzeigen und zu debuggen. Das Festlegen eines Haltepunkts ist daher nicht hilfreich, da er tausende Male getroffen wird.)

heystewart
quelle
Könnten Sie bitte etwas mehr Beschreibung zu der von Ihnen bereitgestellten Erklärung hinzufügen?
Abarisone
6
Dies ist das einzige, was ich zur Arbeit bringen könnte, wenn es vorhanden 'use strict';ist. Hat mir die Infos gegeben, die ich brauchte - danke!
Jeremy Harris
4
In Bezug auf die Begrenzung der Stapellänge ... können Sie dies mit "Error.stackTraceLimit = Infinity" ändern.
Tom
(neuer Fehler ("StackLog")). stack.split ("\ n") erleichtert das Lesen.
Teoman Shipahi
36

Wenn Sie es nicht in IE <11 ausführen möchten, ist console.trace () geeignet .

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4
Gummis
quelle
Es funktioniert! Sollte mehr Up-
Votes
22

Sie können Function.Caller verwenden, um die aufrufende Funktion abzurufen. Die alte Methode mit argument.caller gilt als veraltet.

Der folgende Code veranschaulicht seine Verwendung:

function Hello() { return Hello.caller;}

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

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

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

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

Greg
quelle
1
Dies ist heutzutage die richtige Antwort. Sie können keine argument.caller.callee-Sachen mehr machen. Ich wünschte, wir könnten dies nach oben bringen, da alle anderen Sachen jetzt veraltet sind.
Coblr
4
Scheint, dass dies im strengen Modus nicht möglich ist? Cannot access caller property of a strict mode function
Zach Lysobey
Function.caller hat bei mir auch im strengen Modus nicht funktioniert. Auch nach MDN , function.caller ist Nicht-Standard und sollte nicht in der Produktion verwendet werden. Es könnte jedoch zum Debuggen funktionieren.
jkdev
Ich hatte kein Problem mit Nicht-Standard, wenn es in Node funktionierte, aber es ist einfach nicht im strengen Modus erlaubt (ich habe auf Node 6.10 getestet). Gleiches gilt für 'Argumente'. Ich erhalte die Fehlermeldung: '' 'Aufrufer' und 'Argumente' sind eingeschränkte Funktionseigenschaften und können in diesem Zusammenhang nicht aufgerufen werden. "
Tom
21

Ich würde das tun:

function Hello() {
  console.trace();
}
anorganik
quelle
Das funktioniert super! sollte als die richtige Antwort akzeptiert werden, da andere Wege alt sind \ nicht mehr funktionieren
Yuval Pruss
19
function Hello() {
    alert(Hello.caller);
}
Shadow2531
quelle
1
Und nur für den Funktionsnamen verwenden Sie Hello.caller.name
vanval
das gleiche wiearguments.callee.caller.toString()
user2720864
Dies sollte die richtige Antwort sein, zumindest für 2016
Daniel
Dies ist kein Standard-Track, funktioniert aber ab ECMAScript 5.
Obinna Nwakwue
1
@ Daniel: Nein, das sollte es nicht. Siehe developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Dascalescu
18

Es ist sicherer zu verwenden, *arguments.callee.callerda arguments.calleres veraltet ist ...

Pablo Cabrera
quelle
36
arguments.calleewird auch in ES5 nicht mehr unterstützt und im strengen Modus entfernt.
Nyuszika7h
2
Gibt es eine Alternative? Bearbeiten: arguments.calleewar eine schlechte Lösung für ein Problem, das jetzt besser gelöst wurde. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Matthew
16

Sieht so aus, als wäre dies eine ziemlich gelöste Frage, aber ich habe kürzlich herausgefunden, dass Angerufene im "strengen Modus" nicht erlaubt sind. Deshalb habe ich für meinen eigenen Gebrauch eine Klasse geschrieben, die den Pfad erhält, von dem aus sie aufgerufen wird. Es ist Teil einer kleinen Hilfsbibliothek. Wenn Sie den Code Standalone verwenden möchten, ändern Sie den Offset, der zum Zurückgeben der Stapelverfolgung des Aufrufers verwendet wird (verwenden Sie 1 anstelle von 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('.');
  };
}
QueueHammer
quelle
Funktioniert bei mir nicht mit function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()in der Konsole (habe es nicht in einer Datei versucht), scheint aber eine vernünftige Idee zu haben. Sollte aus Gründen der Sichtbarkeit ohnehin positiv bewertet werden.
Ninjagecko
Die Idee ist großartig. Ich analysiere anders, aber in nw.js Apps ist dies wirklich die einzige Idee, die das gibt, wonach ich suche.
Andrew Grothe
Bitte geben Sie ein Beispiel für den Aufruf dieser Funktion.
pd_au
11

Versuchen Sie, darauf zuzugreifen:

arguments.callee.caller.name
user15566
quelle
1
Dies ist seit vielen Jahren veraltet .
Dan Dascalescu
11

Protokollieren Sie einfach Ihren Fehlerstapel auf der Konsole. Sie können dann wissen, wie Sie angerufen werden

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

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

sello()

Prasanna
quelle
10

Verwenden Sie sowohl im ES6- als auch im Strict-Modus Folgendes, um die Anruferfunktion zu erhalten

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

Bitte beachten Sie, dass die obige Zeile eine Ausnahme auslöst, wenn kein Aufrufer oder kein vorheriger Stapel vorhanden ist. Verwenden Sie entsprechend.

VanagaS
quelle
Um Angerufene (den aktuellen Funktionsnamen) zu erhalten, verwenden Sie: console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
VanagaS
10

Update 2018

callerist im strengen Modus verboten . Hier ist eine Alternative mit dem (nicht standardmäßigen) ErrorStapel .

Die folgende Funktion scheint die Aufgabe in Firefox 52 und Chrome 61-71 zu erfüllen, obwohl ihre Implementierung viele Annahmen über das Protokollierungsformat der beiden Browser macht und mit Vorsicht verwendet werden sollte, da sie eine Ausnahme auslöst und möglicherweise zwei reguläre Ausdrücke ausführt Matchings bevor es fertig ist.

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

Rovanion
quelle
4
Das ist unglaublich und auch schrecklich.
Ian
Ich habe "foo angerufen mit: hi there", aber foo wurde nicht mit "hi there" aufgerufen , log wurde mit "hi there"
aufgerufen
Richtig, es gab einen "falsch platzierten Modifikator" in der Grammatik der Fehlermeldung. Es sollte heißen "Protokoll wurde von Funktion f aufgerufen, es wollte, dass die Nachricht X gedruckt wird", aber so kurz wie möglich.
Rovanion
7

Ich wollte hier meine Geige hinzufügen:

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

Ich habe getestet, dass dies Chrom, Safari und IE (10 und 8) ist. Funktioniert gut. Es gibt nur eine Funktion, die wichtig ist. Wenn Sie also Angst vor der großen Geige haben, lesen Sie weiter unten.

Hinweis: In dieser Geige befindet sich eine ganze Menge meiner eigenen "Boilerplate". Sie können all das entfernen und Splits verwenden, wenn Sie möchten. Es ist nur ein ultra-sicherer Satz von Funktionen, auf die ich mich verlassen kann.

Es gibt dort auch eine "JSFiddle" -Vorlage, die ich für viele Geigen verwende, um einfach schnell zu fummeln.

Bladnman
quelle
Ich frage mich, ob Sie die "Helfer" in einigen Fällen als Erweiterungen für den Prototyp hinzufügen könnten, zum Beispiel:String.prototype.trim = trim;
autistisch
6

Wenn Sie nur den Funktionsnamen und nicht den Code und eine browserunabhängige Lösung wünschen, verwenden Sie Folgendes:

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

Beachten Sie, dass das oben Gesagte einen Fehler zurückgibt, wenn keine Aufruferfunktion vorhanden ist, da das Array kein [1] -Element enthält. Verwenden Sie zum Umgehen Folgendes:

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]);
JoolzCheat
quelle
1
Dies ist seit vielen Jahren veraltet .
Dan Dascalescu
5

Ich möchte Sie nur wissen lassen, dass auf PhoneGap / Android das nicht zu namefunktionieren scheint. Aber arguments.callee.caller.toString()wird den Trick machen.

Pablo Armentano
quelle
4

Hier ist alles , aber das functionnameist gestrippt aus caller.toString(), 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>
BrazFlat
quelle
Dies gibt immer noch die gesamte Methodendeklaration zurück
Maslow
3

Die Antwort von heystewart und die Antwort von JiarongWu erwähnten beide, dass das ErrorObjekt Zugriff auf die hat stack.

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 zeigen den Stapel in verschiedenen Zeichenfolgenformaten:

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 setzen den Stack mit var stack = (new Error()).stack. In Internet Explorer ist der Stapel undefiniert - Sie müssen eine echte Ausnahme auslösen, um den Stapel abzurufen.

Fazit: Mit dem stackim ErrorObjekt kann festgestellt werden, dass "main" der Aufrufer von "Hello" ist . Tatsächlich funktioniert es in Fällen, in denen der callee/ caller-Ansatz nicht funktioniert. Es zeigt Ihnen auch den Kontext, dh die Quelldatei und die Zeilennummer. Es sind jedoch Anstrengungen erforderlich, um die Lösung plattformübergreifend zu gestalten.

Stephen Quan
quelle
2

Beachten Sie, dass Sie Function.caller in Node.js nicht verwenden können. Verwenden Sie stattdessen das Anrufer-ID- Paket. Zum Beispiel:

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
    }
    */
}
ns16
quelle
1

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

Arbeitete für mich in Firefox-21 und Chrom-25.

Diego Augusto Molina
quelle
Versuchen Sie dies für rekursive Funktionen.
Daniel1426
arguments.calleeist seit vielen Jahren veraltet .
Dan Dascalescu
1

Eine andere Möglichkeit, dieses Problem zu umgehen, besteht darin, einfach den Namen der aufrufenden Funktion als Parameter zu übergeben.

Zum Beispiel:

function reformatString(string, callerName) {

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

    return string;
}

Jetzt können Sie die Funktion folgendermaßen aufrufen:

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

    reformatString(myString, function.name);
}

In meinem Beispiel wird eine fest codierte Überprüfung des Funktionsnamens verwendet, aber Sie können problemlos eine switch-Anweisung oder eine andere Logik verwenden, um dort das zu tun, was Sie möchten.

GrayedFox
quelle
Ich glaube, dies löst zum größten Teil auch Probleme mit der Cross-Browser-Kompatibilität. Aber bitte testen Sie dies, bevor Sie davon ausgehen, dass es wahr ist! ( beginnt zu schwitzen )
GrayedFox
1

Soweit ich weiß, haben wir zwei Möglichkeiten dafür aus bestimmten Quellen wie diesen:

  1. Argumente.Caller

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

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

Denke du hast deine Antwort :).

Abrar Jahin
quelle
Dies ist seit vielen Jahren veraltet und Function.caller funktioniert nicht im strengen Modus.
Dan Dascalescu
1

Warum alle oben genannten Lösungen wie eine Raketenwissenschaft aussehen. In der Zwischenzeit sollte es nicht komplizierter sein als dieses Snippet. Alle Credits an diesen Kerl

Wie finden Sie die Aufruferfunktion in JavaScript heraus?

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)]
Anonym
quelle
3
Dies ist, was ich damit benutze: TypeError: Auf die Eigenschaften 'caller', 'callee' und 'arguments' kann möglicherweise nicht über Funktionen des strengen Modus oder die Argumente-Objekte für Aufrufe an sie zugegriffen werden. Irgendwelche Ideen, wie man das im strengen Modus macht?
hard_working_ant
1

Ich versuche, mit dieser Frage sowohl die Frage als auch das aktuelle Kopfgeld anzusprechen.

Die Prämie erfordert, dass der Anrufer im strengen Modus erhalten wird, und die einzige Möglichkeit, dies zu sehen, besteht darin, auf eine außerhalb deklarierte Funktion zu verweisen des strengen Modus .

Das Folgende ist beispielsweise nicht Standard, wurde jedoch mit früheren (29.03.2016) und aktuellen (1. August 2018) Versionen von Chrome, Edge 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();

autistisch
quelle
Netter Hack, funktioniert aber nicht für ES5-Module, die sich vollständig im strengen Modus befinden .
Dan Dascalescu
0

Wenn Sie die Funktionalität aus irgendeinem Grund wirklich benötigen und möchten, dass sie browserübergreifend kompatibel ist und sich nicht um strenge Dinge kümmert und vorwärtskompatibel ist, übergeben Sie diese Referenz:

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
}
Mario PG
quelle
0

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

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

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 folgendermaßen 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
JiarongWu
quelle