function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Gibt es eine Möglichkeit, den Aufrufstapel herauszufinden?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Gibt es eine Möglichkeit, den Aufrufstapel herauszufinden?
Antworten:
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());
}
arguments.callee.caller.name
erhält den Namen der Funktion.
'use strict';
könnte also helfen.
arguments
Auf 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.
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:
Es ist sehr langsam, den Stack-Trace zu erhalten. Seien Sie also vorsichtig (lesen Sie dies für weitere Informationen).
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 function
und behandeln ihn als anonyme Funktion. Ein nicht einmal Chrome kann den Klass
Namen 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 .
Nicht alle Browser geben Ihnen die gleichen Informationen. Das heißt, Parameter, Codespalte usw.
Ü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 function
Schlüsselwort steht. Ich habe keine Möglichkeit gefunden (auch nicht bei Google Chrome), mehr zu erreichen, ohne den Code der gesamten Funktion zu erhalten.
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).
Function.caller
per @ Gregs Antwort
Function.caller
funktioniert jedoch nicht im strengen Modus.
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: Legen Sie einfach den Debugger dort ab, wo Sie den Stapel untersuchen möchten.
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 :(
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.
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.)
'use strict';
ist. Hat mir die Infos gegeben, die ich brauchte - danke!
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
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
Cannot access caller property of a strict mode function
Ich würde das tun:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
Es ist sicherer zu verwenden, *arguments.callee.caller
da arguments.caller
es veraltet ist ...
arguments.callee
wird auch in ES5 nicht mehr unterstützt und im strengen Modus entfernt.
arguments.callee
war eine schlechte Lösung für ein Problem, das jetzt besser gelöst wurde. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
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('.');
};
}
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.
Versuchen Sie, darauf zuzugreifen:
arguments.callee.caller.name
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()
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.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
caller
ist im strengen Modus verboten . Hier ist eine Alternative mit dem (nicht standardmäßigen) Error
Stapel .
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();
}());
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.
String.prototype.trim = trim;
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]);
Ich möchte Sie nur wissen lassen, dass auf PhoneGap / Android das nicht zu name
funktionieren scheint. Aber arguments.callee.caller.toString()
wird den Trick machen.
Hier ist alles , aber das functionname
ist 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>
Hier ist eine Funktion, um eine vollständige Stapelverfolgung zu erhalten :
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
Die Antwort von heystewart und die Antwort von JiarongWu erwähnten beide, dass das Error
Objekt 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 stack
im Error
Objekt 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.
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
}
*/
}
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.
arguments.callee
ist seit vielen Jahren veraltet .
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.
Soweit ich weiß, haben wir zwei Möglichkeiten dafür aus bestimmten Quellen wie diesen:
function whoCalled()
{
if (arguments.caller == null)
console.log('I was called from the global scope.');
else
console.log(arguments.caller + ' called me!');
}
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 :).
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)]
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();
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
}
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