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 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?
Réponses:
function Hello()
{
alert("caller is " + Hello.caller);
}
Notez que cette fonctionnalité n'est pas standard , à partir de Function.caller
:
Non standard
Cette fonctionnalité n'est pas standard et n'est pas sur une piste standard. Ne l'utilisez pas sur des sites de production 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 dans Javascript moderne:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
obtiendra le nom de la fonction.
'use strict';
pourrait donc être utile.
arguments
PEUT être accessible à partir d'une fonction en mode strict, il serait stupide de le déprécier. tout simplement pas de function.arguments de l'extérieur. De plus, si vous avez un argument nommé, sa forme arguments [i] ne suivra pas les modifications que vous apportez à la version nommée dans la fonction.
Vous pouvez trouver l'intégralité de la trace de la pile à l'aide d'un 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:
Il est très lent d'obtenir la trace de la pile, alors soyez prudent (lisez ceci pour en savoir plus).
Vous devrez définir des noms de fonction pour que la trace de 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 s'attendront à un nom de fonction juste après le mot-clé function
et le traiteront comme une fonction anonyme. Un même Chrome ne pourra pas utiliser le Klass
nom si vous ne donnez pas le nom kls
à la fonction.
Et au fait, vous pouvez passer à la fonction printStackTrace l'option {guess: true}
mais je n'ai trouvé aucune amélioration réelle en faisant cela.
Tous les navigateurs ne vous donnent pas les mêmes informations. Autrement dit, les paramètres, la colonne de code, etc.
Soit dit en passant, si vous ne voulez que 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 function
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.
Et résumant le reste des meilleures réponses (par Pablo Cabrera, nourdine et Greg Hewgill). La seule chose multi-navigateur et vraiment sûre que vous pouvez utiliser est:
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 le StackTrace et le nom de la fonction d'appel (bien qu'ils ne soient pas multi-navigateurs).
Function.caller
selon la réponse de @ Greg
Function.caller
ne fonctionnera pas en mode strict, cependant.
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: déposez simplement le débogueur à l'endroit où vous souhaitez enquêter sur la pile.
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, par exemple de "Bonjour" à "Ciao", et toujours faire fonctionner le tout.
Dans ce dernier cas, si vous décidez de refactoriser le nom de la fonction invoquée (Bonjour), vous devrez modifier toutes ses occurrences :(
Vous pouvez obtenir la trace de pile complète:
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.
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 cela pour collecter des piles d'appels dans un constructeur de bas niveau pendant l'exécution, pour afficher et déboguer plus tard, donc la définition d'un point d'arrêt n'est pas utile car il sera atteint des milliers de fois)
'use strict';
en place. M'a donné les informations dont j'avais besoin - merci!
Si vous n'allez 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();
}
Notes sur l'argument.caller 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
Cannot access caller property of a strict mode function
Je ferais ceci:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
Il est plus sûr à utiliser *arguments.callee.caller
car il arguments.caller
est obsolète ...
arguments.callee
est également déconseillé dans ES5 et supprimé en mode strict.
arguments.callee
était une mauvaise solution à un problème qui a maintenant été mieux résolu developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
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 propre usage, j'ai écrit une classe qui obtiendra le chemin d'où elle s'appelle. Cela fait partie d'une petite bibliothèque d'aide et si vous souhaitez utiliser le code de manière autonome, changez l'offset utilisé pour renvoyer 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('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
dans la console (je n'ai pas essayé dans un fichier), mais semble avoir une idée raisonnable. Doit être voté de toute façon pour la visibilité.
Essayez d'accéder à ceci:
arguments.callee.caller.name
Consignez simplement votre console dans la pile des erreurs. Vous pouvez alors savoir comment vous appelez
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
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èvera une exception s'il n'y a aucun appelant ou aucune pile précédente. Utilisez en conséquence.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
caller
est interdit en mode strict . Voici une alternative utilisant la pile (non standard)Error
.
La fonction suivante semble faire le travail dans Firefox 52 et Chrome 61-71 bien que son implémentation fasse beaucoup d'hypothèses sur le format de journalisation des deux navigateurs et doit être utilisée avec prudence, car elle lève une exception et exécute éventuellement deux expressions régulières 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 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();
}());
Je voulais ajouter mon violon ici pour cela:
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 seule fonction qui compte, donc si vous avez peur du gros violon, lisez ci-dessous.
Remarque: il y a une bonne quantité de mon propre "passe-partout" dans ce violon. Vous pouvez supprimer tout cela et utiliser des scissions si vous le souhaitez. C'est juste un ensemble de fonctions ultra-sûres sur lesquelles je viens de compter.
Il y a aussi un modèle "JSFiddle" que j'utilise pour de nombreux violons pour un simple violon rapide.
String.prototype.trim = trim;
Si vous souhaitez 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 retournera 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 ce 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 faire savoir que sur PhoneGap / Android du name
doesnt semblent fonctionner. Mais arguments.callee.caller.toString()
fera l'affaire.
Ici, tout sauf le functionname
est supprimé 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 stacktrace 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 ont toutes deux mentionné que l' Error
objet 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éfiniront la pile avec var stack = (new Error()).stack
. Dans Internet Explorer, la pile ne sera pas définie - vous devez lever 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 stack
dans l' Error
objet. 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 multiplateforme.
Notez que vous ne pouvez pas utiliser Function.caller dans Node.js, utilisez plutôt le package id-appelant . Par exemple:
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
}
*/
}
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;
}
A travaillé pour moi dans Firefox-21 et Chromium-25.
arguments.callee
est obsolète depuis de nombreuses années .
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.
Pour autant que je sache, nous avons 2 voies 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 que vous avez votre réponse :).
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 découvrir 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 nécessite que l'appelant soit obtenu en mode strict , et la seule façon dont je peux voir cela est de se référer à une fonction déclarée en dehors du mode strict.
Par exemple, ce qui suit n'est pas 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();
Si vous avez vraiment besoin de la fonctionnalité pour une raison quelconque et que vous souhaitez qu'elle soit compatible avec tous les navigateurs et ne vous inquiétez pas pour les choses strictes et la compatibilité ascendante, passez une 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 morceau de 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