Question

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?

Était-ce utile?

La solution

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 à l'avenir.

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

Autres conseils

StackTrace

Vous pouvez trouver la trace entière de la pile en utilisant un code spécifique au navigateur. La bonne chose est que quelqu'un l'a déjà fait ; voici le code de projet sur GitHub .

Mais toutes les nouvelles ne sont pas bonnes:

  1. Il est très lent d'obtenir la trace de la pile, soyez donc prudent (lisez this pour plus d'informations).

  2. 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 attendent un nom de fonction juste après le mot clé function et le traitent comme une fonction anonyme. Même pas Google 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 faisant cela.

  3. Tous les navigateurs ne vous donnent pas les mêmes informations. En d'autres termes, les paramètres, la colonne de code, etc.


Nom de la fonction de l'appelant

À 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 après le mot clé <=>. 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.


Code de fonction de l'appelant

Et résumant le reste des meilleures réponses (de Pablo Cabrera, Nourdine et Greg Hewgill). La seule chose réellement inter-navigateur et réellement sûre que vous pouvez utiliser est la suivante:

arguments.callee.caller.toString();

Qui affichera 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 cross-browser).

Pour récapituler (et préciser) ...

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 changer le nom de la fonction, par exemple, à partir de & "Hello &"; pour " Ciao " ;, et toujours faire fonctionner le tout.

Dans ce dernier cas, si vous décidez de refactoriser le nom de la fonction invoquée (Hello), vous devrez 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: cela 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 simplement les outils de développement de votre navigateur. Voici à quoi ça ressemble dans Chrome: entrer la description de l'image ici 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 d'abord venu sur cette page.

(J'utilise ceci pour collecter des piles d'appels dans un constructeur de bas niveau pendant l'exécution, pour les afficher et les déboguer plus tard. La définition d'un point d'arrêt n'est donc pas utile car il sera touché des milliers de fois.

Si vous n’allez pas le lancer dans IE < 11 Ensuite, 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 l'argument.caller obsolète: 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 car arguments.caller est obsolète ...

.

Cela semble être une question assez résolue, mais j'ai récemment découvert que callee n’est pas autorisé en "mode strict" . Pour ma propre utilisation, j’ai écrit une classe qui obtiendra le chemin d’origine. Il s'agit d'une partie d'une petite bibliothèque d'aide et si vous souhaitez utiliser le code autonome, modifiez le 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 vous suffit de vous connecter pour consigner votre pile d’erreur 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 cela:

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

J'ai testé le chrome, le safari et IE (10 et 8). Fonctionne bien. Une seule fonction compte. Si le grand violon vous fait peur, lisez la suite.

Remarque: Il y a une bonne quantité 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 ultra-sûr & Quot; ensemble de fonctions sur lesquelles je compte désormais.

Il existe également un " JSFiddle & "; modèle là-bas que j'utilise pour de nombreux violons à jouer rapidement.

Mise à jour 2018

caller interdit en mode strict . Voici une alternative utilisant le (non standard) Error pile .

La fonction suivante semble faire l'affaire dans Firefox 52 et Chrome 61-71, bien que son implémentation suppose de nombreuses hypothèses sur le format de journalisation des deux navigateurs. Elle doit être utilisée avec prudence, car elle génère une exception et éventuellement exécute deux correspondances regex avant d’être effectuées.

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

Si vous souhaitez uniquement 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 d'appelant 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 tiens simplement à vous informer que sur PhoneGap / Android , name ne semble pas fonctionner. Mais arguments.callee.caller.toString() fera l'affaire.

Ici, tout sauf le 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>

voici une fonction pour obtenir le chemin de pile complet :

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

La réponse de heystewart et La réponse de JiarongWu mentionnait à la fois que l'objet Error avait accès au 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 le callee dans l'objet caller. En fait, cela fonctionnera dans les cas où l'approche <=> / <=> 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.

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 Chromium-25.

Une autre solution 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;
}

Vous pouvez maintenant appeler la fonction comme suit:

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à.

Pour autant que je sache, nous avons 2 moyens 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. 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;
        }
    }
    

Vous pensez avoir votre réponse:).

Pourquoi toutes les solutions ci-dessus ressemblent-elles à une fusée. En attendant, cela ne devrait pas être plus compliqué que cet extrait. Tous les crédits à ce gars

Comment savoir 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)]

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 consiste à faire référence à une fonction déclarée en dehors du mode strict.

Par exemple, les éléments suivants sont non standard, mais ont été testés 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();

Si vous avez réellement besoin de cette fonctionnalité pour une raison quelconque et souhaitez la rendre compatible avec tous les navigateurs et ne vous inquiétez pas pour les commandes strictes et la compatibilité en aval, 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
}

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

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 comme chaîne ou callstack), je publie 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();

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top