function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Existe-t-il un moyen de connaître la pile d'appels?
function Hello()
{
alert("caller is " + Hello.caller);
}
Notez que cette fonctionnalité est non standard, de Function.caller
:
Non standard
Cette fonctionnalité n'est pas standard et ne fait pas partie des standards. Ne l'utilisez pas sur les sites de production faisant face au Web: cela ne fonctionnera pas pour tous les utilisateurs. Il peut également y avoir de grandes incompatibilités entre les implémentations et le comportement peut changer dans le futur.
Ce qui suit est l'ancienne réponse de 2008, qui n'est plus prise en charge par le Javascript moderne:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
Vous pouvez trouver toute la trace de la pile à l'aide du code spécifique au navigateur. La bonne chose est quelqu'un l'a déjà fait ; voici le code du projet sur GitHub .
Mais toutes les nouvelles ne sont pas bonnes:
Il est vraiment très lent d’obtenir la trace de la pile, alors soyez prudent (lisez this } _ pour plus).
Vous devrez définir des noms de fonction pour que la trace de la pile soit lisible. Parce que si vous avez un code comme celui-ci:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
Google Chrome alertera ... kls.Hello ( ...
, mais la plupart des navigateurs attendront un nom de fonction juste après le mot clé function
et le traiteront comme une fonction anonyme. Pas même Chrome pourra 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 procédant de la sorte.
Tous les navigateurs ne vous donnent pas les mêmes informations. C'est-à-dire des paramètres, une colonne de code, etc.
À propos, si vous voulez seulement le nom de la fonction appelant (dans la plupart des navigateurs, mais pas dans IE), vous pouvez utiliser:
arguments.callee.caller.name
Mais notez que ce nom sera celui qui suit le mot clé function
. Je n'ai trouvé aucun moyen (même sur Google Chrome) d'obtenir plus que cela sans obtenir le code de la fonction entière.
Et résumant le reste des meilleures réponses (de Pablo Cabrera, Nourdine et Greg Hewgill). La seule chose vraiment sûre et multi-navigateurs que vous pouvez utiliser est:
arguments.callee.caller.toString();
Ce qui montrera le code de la fonction appelant. Malheureusement, cela ne me suffit pas, et c’est pourquoi je vous donne des conseils pour StackTrace et le nom de la fonction d’appel (bien qu’ils ne soient pas multi-navigateurs).
Vous pouvez obtenir le stacktrace complet:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Jusqu'à l'appelant est null
.
Remarque: cela provoque une boucle infinie sur les fonctions récursives.
Pour récapituler (et clarifier) ...
ce code:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
est équivalent à ceci:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Il est clair que le premier bit est plus portable, car vous pouvez modifier le nom de la fonction, par exemple de "Hello" à "Ciao", tout en maintenant le fonctionnement complet.
Dans ce dernier cas, si vous décidez de refactoriser le nom de la fonction invoquée (Hello), vous devrez changer toutes ses occurrences :(
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 simplement les outils de développement de votre navigateur. Voici à quoi cela ressemble dans Chrome: Il suffit de déposer le débogueur à l’endroit où vous souhaitez examiner la pile.
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 que cela limite la longueur de la pile à 10, c'est pourquoi je suis venu à cette page en premier lieu.
(J'utilise ceci pour collecter des piles d'appels dans un constructeur de bas niveau lors de l'exécution, pour afficher et déboguer ultérieurement. La définition d'un point d'arrêt n'est donc pas utile car il sera touché des milliers de fois.)
Si vous ne voulez pas l'exécuter dans IE <11, alors console.trace () conviendrait.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Vous pouvez utiliser Function.Caller pour obtenir la fonction appelante. 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 obsolete argument.caller: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller
Attention, 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 préférable d'utiliser *arguments.callee.caller
puisque arguments.caller
est deprecated ...
On dirait que c'est une question assez résolue, mais j'ai récemment découvert que l'appelé n'est pas autorisé en «mode strict» donc pour mon usage personnel, j'ai écrit un cours qui obtiendra le chemin d'accès. C'est une partie d'une petite bibliothèque d'aide et si vous voulez utiliser le code autonome, changez l'offset utilisé pour retourner la trace de 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('.');
};
}
Je voudrais faire ceci:
function Hello() {
console.trace();
}
Essayez d'accéder à ceci:
arguments.callee.caller.name
Il suffit de consigner votre pile d’erreur dans le journal. Vous pouvez alors savoir comment on vous appelle
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Je voulais ajouter mon violon ici pour ceci:
http://jsfiddle.net/bladnman/EhUm3/
J'ai testé c'est chrome, safari et IE (10 et 8). Fonctionne bien. Il n'y a qu'une fonction qui compte, alors si vous êtes effrayé par le grand violon, lisez ci-dessous.
Note: .__ Il y a pas mal de mon propre "passe-partout" dans ce violon. Vous pouvez supprimer tout cela et utiliser des split si vous le souhaitez. C’est juste un ensemble de fonctions ultra-sûres sur lesquelles je m’appuie.
Il existe également un modèle "JSFiddle" que j'utilise dans de nombreux violons pour jouer rapidement du violon.
Si vous souhaitez simplement le nom de la fonction et non le code et souhaitez une solution indépendante du navigateur, utilisez les éléments suivants:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
Notez que ce qui précède renvoie une erreur s'il n'y a pas de fonction caller car il n'y a pas d'élément [1] dans le tableau. Pour contourner le problème, 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 veux juste vous dire que sur PhoneGap/Android la name
ne semble pas fonctionner. Mais arguments.callee.caller.toString()
fera l'affaire.
Ici, tout sauf la functionname
est retiré 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>
la réponse de heystewart et la réponse de JiarongWu les deux ont 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;
}
// 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();
Différents navigateurs affichent la pile dans différents formats de chaîne:
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)
La plupart des navigateurs définissent la pile avec var stack = (new Error()).stack
. Dans Internet Explorer, la pile sera indéfinie - vous devez générer une véritable exception pour récupérer la pile.
Conclusion: Il est possible de déterminer "principal" est l'appelant à "Bonjour" en utilisant la variable stack
dans l'objet Error
. En fait, cela fonctionnera dans les cas où l'approche callee
/caller
ne fonctionne pas. Il vous montrera également le contexte, c’est-à-dire le fichier source et le numéro de ligne. Cependant, des efforts sont nécessaires pour rendre la solution multi-plateforme.
voici une fonction pour obtenir un stacktrace complet :
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
caller
est interdit en mode strict . Voici une alternative utilisant la pile (non standard) Error
.
La fonction suivante semble faire l'affaire dans Firefox 52 et Chrome 61-71, bien que son implémentation suppose beaucoup d'hypothèses sur le format de journalisation des deux navigateurs. appariements avant d'être fait.
'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();
}());
Pourquoi toutes les solutions ci-dessus ressemblent à une science de fusée. En attendant, cela ne devrait pas être plus compliqué que cet extrait. Tous les crédits à ce gars
Comment trouvez-vous la fonction 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)]
Pour autant que je sache, nous avons 2 moyens pour cela à partir de sources données comme celle-ci-
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;
}
}
Pensez-vous avoir votre réponse :).
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;
}
Travaillé pour moi dans Firefox-21 et Chrome-25.
En mode ES6 et strict, utilisez ce qui suit pour obtenir la fonction appelant
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Veuillez noter que la ligne ci-dessus lève une exception s'il n'y a ni appelant ni pile précédente. Utilisez en conséquence.
J'essaie de répondre à la fois à la question et à la prime actuelle avec cette question.
La prime exige que l'appelant soit obtenu en mode strict , et la seule façon de le savoir est de faire référence à une fonction déclarée outside du mode strict.
Par exemple, ce qui suit est non standard, mais a été testé avec les versions précédentes (29/03/2016) et actuelles (1er août 2018) 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);
}
main();
Une autre façon de contourner ce problème consiste à simplement passer le nom de la fonction appelante 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 une vérification codée en dur du nom de la fonction, mais vous pouvez facilement utiliser une instruction switch ou une autre logique pour faire ce que vous voulez là.
Si vous avez réellement besoin de cette fonctionnalité pour quelque raison que ce soit et que vous souhaitez qu’elle soit compatible avec tous les navigateurs et ne vous inquiétez pas pour les commandes strictes et qu’elle soit compatible avec la transmission directe, transmettez 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
}
Comme aucune des réponses précédentes ne fonctionne comme ce que je cherchais (obtenir uniquement le dernier appelant de fonction et non une fonction de chaîne ou de callstack), je poste ici ma solution pour ceux qui sont comme moi et espèrent que cela fonctionnera pour eux:
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();
Je pense que le code suivant 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