Comment découvrez-vous la fonction d'appelant en JavaScript?

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

Existe-t-il un moyen de découvrir la pile d'appels?

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

Trace de la pile

Vous pouvez trouver toute la trace de la pile à l'aide du code spécifique au navigateur. La bonne chose est que quelqu'un l'a déjà fait ; Voici le code du projet sur GitHub .

Mais toutes les nouvelles ne sont pas bonnes:

  1. Il est vraiment lent d'obtenir la trace de la pile, alors soyez prudent (lisez ceci pour plus d'informations).

  2. Vous devrez définir les noms des fonctions pour que la trace de la pile soit lisible. Parce que si vous avez un code comme ceci:

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

    Google Chrome alerte ... kls.Hello ( ... mais la plupart des navigateurs s'attendront à un nom de fonction juste après la function mot-clé et le traiteront comme une fonction anonyme. Un Chrome même ne pourra pas utiliser le nom Klass si vous Ne donnez pas le nom kls à la fonction.

    Et en passant, vous pouvez passer à la fonction printStackTrace l'option {guess: true} mais je n'ai trouvé aucune amélioration réelle en faisant cela.

  3. Tous les navigateurs ne vous donnent pas la même information. C'est-à-dire les paramètres, la colonne du code, etc.


Nom de la fonction de l'appelant

En passant, si vous voulez seulement le nom de la fonction appelant (dans la plupart des navigateurs, mais pas IE), vous pouvez utiliser:

 arguments.callee.caller.name 

Mais notez que ce nom sera celui après le mot clé de la function . Je n'ai trouvé aucun moyen (même sur Google Chrome) d'obtenir plus que cela sans avoir le code de la fonction entière.


Code de fonction de l'appelant

Et résumant le reste des meilleures réponses (par Pablo Cabrera, nourdine et Greg Hewgill). Le seul navigateur croisé et la chose vraiment sûre que vous pouvez utiliser est:

 arguments.callee.caller.toString(); 

Ce qui montrera le code de la fonction d'appelant. Malheureusement, cela ne me suffit pas, et c'est pourquoi je vous donne des conseils pour StackTrace et le nom de la fonction appelante (bien qu'ils ne soient pas des navigateurs multiples).

Pour récapituler (et le rendre plus clair) …

Ce code:

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

Est équivalent à ceci:

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

De toute évidence, le premier bit est plus portable, car vous pouvez changer le nom de la fonction, parlez de "Bonjour" à "Ciao", et obtenez toujours tout le travail.

Dans ce dernier cas, si vous décidez de refactoriser le nom de la fonction invoquée (Bonjour), vous devriez changer toutes ses occurrences 🙁

Vous pouvez obtenir le stacktrace complet:

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

Jusqu'à ce que l'appelant soit null .

Remarque: il provoque une boucle infinie sur les fonctions récursives.

Je sais que vous avez mentionné "en Javascript", mais si le but est le débogage, je pense qu'il est plus facile d'utiliser les outils de développement de votre navigateur. C'est comme cela que l'on trouve dans Chrome: Entrez la description de l'image ici Il suffit de déposer le débogueur où vous voulez enquêter sur la pile.

Vous pouvez utiliser Function.Caller pour obtenir la fonction d'appel. L'ancienne méthode utilisant argument.caller est considérée comme obsolète.

Le code suivant illustre son utilisation:

 function Hello() { return Hello.caller;} Hello2 = function NamedFunc() { return NamedFunc.caller; }; function main() { Hello(); //both return main() Hello2(); } 

Remarques sur l'argument classé obsolète: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Soyez conscient que Function.caller n'est pas standard: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

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

Il est plus sûr d'utiliser *arguments.callee.caller puisque arguments.caller est obsolète

J'utilise habituellement (new Error()).stack dans Chrome. La bonne chose est que cela vous donne également les numéros de ligne où l'appelant a appelé la fonction. L'inconvénient est qu'il limite la longueur de la pile à 10, c'est pourquoi je suis venu sur cette page en premier lieu.

(J'utilise ceci pour collecter des appels dans un constructeur de bas niveau pendant l'exécution, pour afficher et déboguer plus tard, afin de définir un point d'interruption n'est pas utile puisqu'il sera touché des milliers de fois)

On dirait que c'est une question tout à fait résolue, mais j'ai récemment découvert que l' appelant n'est pas autorisé en mode «strict», donc, pour ma propre utilisation, j'ai écrit une classe qui obtiendra le chemin d'où elle s'appelle. Cela fait partie d'une petite bibliothèque auxiliaire et si vous souhaitez utiliser le code en mode autonome, modifiez le décalage utilisé pour renvoyer la trace de la pile de l'appelant (utilisez 1 au lieu de 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('.'); }; } 

Essayez d'accéder à ceci:

 arguments.callee.caller.name 

Si vous ne l'exécutez pas dans IE <11, alors console.trace () serait approprié .

 function main() { Hello(); } function Hello() { console.trace() } main() // Hello @ VM261:9 // main @ VM261:4 

Si vous voulez simplement le nom de la fonction et non le code et souhaitez une solution indépendante du navigateur, utilisez ce qui suit:

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

Notez que ce qui précède renverra une erreur s'il n'y a pas de fonction d'appel, car il n'y a pas d'élément [1] dans le tableau. Pour contourner, utilisez ce qui suit:

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

Je voulais ajouter mon violon ici pour cela:

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

J'ai testé ceci: chrome, safari et IE (10 et 8). Fonctionne bien. Il n'y a qu'une seule fonction qui compte, donc si vous êtes effrayé par le gros violon, lisez ci-dessous.

Note: Il y a une bonne partie de mon propre "boilerplate" dans cette violon. Vous pouvez supprimer tout cela et utiliser split si vous le souhaitez. C'est juste un jeu de fonctions ultra-sécurisé sur lequel je suis venu.

Il existe également un modèle "JSFiddle" là-bas que j'utilise pour de nombreuses violences pour un simple brouillage rapide.

Je veux simplement vous faire savoir que sur PhoneGap / Android, le name semble pas fonctionner. Mais arguments.callee.caller.toString() fera l'affaire.

Ici, tout sauf le nom de functionname est dépouillé de caller.toString() , avec 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> 

Voici une fonction pour obtenir une stacktrace complète :

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

Essayez le code suivant:

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

J'ai travaillé pour moi dans Firefox-21 et Chromium-25.

Pour autant que je sache, nous avons 2 voies pour cela à partir de sources données comme celle-ci –

  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. Fonction.caller

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

Pensez à votre réponse :).

Je tente d'aborder la question et la générosité actuelle avec cette question.

La prime requiert que l'appelant soit obtenu en mode strict , et la seule façon de voir cela fait est de faire référence à une fonction déclarée en dehors du mode strict.

Par exemple, ce qui suit est non standard mais a été testé avec des versions actuelles (29/03/2016) de Chrome, Edge et 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); } 

Pourquoi toutes les solutions ci-dessus ressemblent à une science-roquette. Pendant ce temps, il ne devrait pas être plus compliqué que cet extrait. Tous les crédits à ce type

Comment découvrez-vous la fonction d'appelant en 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)] 

Si vous avez vraiment besoin de la fonctionnalité pour une raison quelconque et que vous voulez qu'il soit compatible avec le navigateur et ne vous inquiétez pas pour des choses strictes et que vous deviez être compatible avec l'avance, passez cette référence:

 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 } 

Une autre façon de résoudre ce problème consiste à simplement passer le nom de la fonction d'appel en tant que paramètre.

Par exemple:

 function reformatString(string, callerName) { if (callerName === "uid") { string = string.toUpperCase(); } return string; } 

Maintenant, vous pouvez appeler la fonction comme ceci:

 function uid(){ var myString = "apples"; reformatString(myString, function.name); } 

Mon exemple utilise un contrôle codé dur du nom de la fonction, mais vous pouvez facilement utiliser une déclaration de commutation ou une autre logique pour faire ce que vous voulez.

Je pense que la pièce de code suivante peut être utile:

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

Exécutez le 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(); 

Le journal ressemble à ceci:

 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 

La réponse de Heystewart et la réponse de JiarongWu ont tous deux mentionné que l'objet Error a accès à la stack .

Voici un exemple:

 function main() { Hello(); } function Hello() { var stack; try { throw new Error(); } catch (e) { stack = e.stack; } // NB 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();