Comment puis-je accéder à un nom de fonction à partir de cette fonction?
// parasitic inheritance
var ns.parent.child = function() {
var parent = new ns.parent();
parent.newFunc = function() {
}
return parent;
}
var ns.parent = function() {
// at this point, i want to know who the child is that called the parent
// ie
}
var obj = new ns.parent.child();
Dans ES5, la meilleure chose à faire est de:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
L'utilisation de Function.caller
n'est pas standard. Function.caller
et arguments.callee
sont tous deux interdits en mode strict.
Edit: la réponse basée sur regex ci-dessous de Nus réalise la même chose, mais a de meilleures performances!
Dans ES6, vous pouvez simplement utiliser myFunction.name
.
Remarque: Attention, certains minificateurs JS risquent d’éliminer les noms de fonctions pour mieux compresser. vous devrez peut-être modifier leurs paramètres pour éviter cela.
ES6 (inspiré par la réponse de sendy halim ci-dessous):
myFunction.name
Explication sur MDN . À partir de 2015, fonctionne dans nodejs et dans tous les principaux navigateurs sauf IE.
Remarque: Sur les fonctions liées, cela donnera "bound <originalName>
". Vous devrez supprimer la "reliure" si vous souhaitez obtenir le nom d'origine.
ES5 (inspiré de la réponse de Vlad):
Si vous avez une référence à la fonction, vous pouvez faire:
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the Word 'function'
// - \s+ at least some white space
// - ([\w\$]+) capture one or more valid JavaScript identifier characters
// - \s* optionally followed by white space (in theory there won't be any here,
// so if performance is an issue this can be omitted[1]
// - \( followed by an opening brace
//
var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )
return result ? result[ 1 ] : '' // for an anonymous function there won't be a match
}
caller
et callee
sont considérés comme obsolètes.[1] Je l'inclue ici car c'est légal et souvent assez d'outils de coloration syntaxique ne tiennent pas compte de l'espace blanc entre le nom de la fonction et la parenthèse. D'autre part, je ne suis au courant d'aucune implémentation de .toString () qui inclura un espace blanc ici, c'est pourquoi vous pouvez l'omettre.
En réponse à la question initiale, je laisserais tomber l'héritage parasite et opterais pour des modèles de conception plus traditionnels OOP. J'ai écrit un TidBits.OoJs pour écrire confortablement le code OOP en JavaScript avec un ensemble de fonctionnalités imitant le langage C++ (pas encore complet, mais surtout).
Je vois dans les commentaires que vous souhaitez éviter de transmettre des informations dont parent
a besoin à son constructeur. Je dois admettre que les modèles de conception traditionnels ne vous épargneront pas celui-ci, car il est généralement considéré comme une bonne chose de rendre vos dépendances évidentes et appliquées.
Je suggérerais également de s'éloigner des fonctions anonymes. Ils ne font que déboguer et profiler un PITA parce que tout s’affiche en tant que "fonction anonyme" et qu’il n’ya aucun avantage pour eux, à ma connaissance.
vous assignez une fonction sans nom à une variable. vous avez probablement besoin d’expression de fonction nommée à la place ( http://kangax.github.com/nfe/ ).
var x = function x() {
console.log( arguments.callee.name );
}
x();
cependant, je ne suis pas sûr de la quantité de navigation croisée qui existe. Il y a un problème avec IE6 qui fait que le nom de votre fonction fuit dans l'étendue externe. de plus, arguments.callee est en quelque sorte obsolète et entraînera une erreur si vous utilisez strict mode
.
N'importe quel constructor
expose une propriété name
, qui est le nom de la fonction. Vous accédez à la constructor
via une instance (en utilisant new
) ou une prototype
:
function Person() {
console.log(this.constructor.name); //Person
}
var p = new Person();
console.log(p.constructor.name); //Person
console.log(Person.prototype.constructor.name); //Person
Cela pourrait fonctionner pour vous:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
lancer foo () affichera "foo" ou undefined si vous appelez depuis une fonction anonyme.
Il fonctionne également avec les constructeurs, auquel cas il afficherait le nom du constructeur appelant (par exemple, "Foo").
Plus d'infos ici: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
Ils prétendent que ce n'est pas standard, mais aussi qu'il est supporté par tous les principaux navigateurs: Firefox, Safari, Chrome, Opera et IE.
Cela ressemble à la chose la plus stupide, celle que j’ai écrite dans ma vie, mais c’est drôle: D
function getName(d){
const error = new Error();
const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=@)/) || [])[0];
const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
const safariMatch = error.stack.split('\n')[0 + d];
// firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
// chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
// safariMatch ? console.log('safariMatch', safariMatch) : void 0;
return firefoxMatch || chromeMatch || safariMatch;
}
d
- profondeur de la pile. 0
- renvoie le nom de cette fonction, 1
- parent, etc.[0 + d]
- juste pour comprendre - ce qui se passe;firefoxMatch
- fonctionne pour le safari, mais j'avais vraiment un peu de temps pour faire des tests, car le propriétaire de mac était revenu après avoir fumé et m'avait chassé: '(
Essai:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
Cette solution ne créait que juste pour le fun ! Ne l'utilisez pas pour de vrais projets. Cela ne dépend pas de la spécification ES, cela dépend uniquement de la réalisation du navigateur. Après la prochaine mise à jour de chrome/firefox/safari, il est peut-être cassé.
Plus que cela, il n'y a pas d'erreur (ha) en cours de traitement - si d
sera plus que la longueur de la pile - vous obtiendrez une erreur;
Pour le modèle de message d'erreur des autres rédacteurs - vous obtiendrez une erreur;
Cela doit fonctionner pour les classes ES6 (.split('.').pop()
), mais vous pouvez toujours obtenir un erorr;
Tu ne peux pas. Les fonctions n'ont pas de noms conformes à la norme (bien que mozilla ait un tel attribut) - elles ne peuvent être attribuées qu'à des variables portant des noms.
Aussi votre commentaire:
// access fully qualified name (ie "my.namespace.myFunc")
se trouve dans la fonction my.namespace.myFunc.getFn
Ce que vous pouvez faire est de retourner le constructeur d’un objet créé par new
Alors tu pourrais dire
var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
Vous pouvez utiliser la propriété name
pour obtenir le nom de la fonction, sauf si vous utilisez une fonction anonyme.
Par exemple:
var Person = function Person () {
this.someMethod = function () {};
};
Person.prototype.getSomeMethodName = function () {
return this.someMethod.name;
};
var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());
essayons maintenant avec la fonction nommée
var Person = function Person () {
this.someMethod = function someMethod() {};
};
maintenant tu peux utiliser
// will return "someMethod"
p.getSomeMethodName()
Vous pouvez utiliser Function.name
:
Dans la plupart des implémentations de JavaScript, une fois que vous avez la référence de votre constructeur dans l'étendue, vous pouvez obtenir son nom de chaîne à partir de sa propriété name (par exemple, Function.name ou Object.constructor.name.
Vous pouvez utiliser Function.callee
:
La méthode native arguments.caller
est obsolète, mais la plupart des navigateurs prennent en charge Function.caller
, qui renverra l’objet appelant (son corps de code): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Caller?redirectlocale=en-US&redirectlug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller
Vous pouvez créer une carte source :
Si vous avez besoin de la signature de fonction littérale (le "nom" de celle-ci) et non de l'objet lui-même, vous devrez peut-être recourir à quelque chose d'un peu plus personnalisé, comme créer une référence à un tableau des valeurs de chaîne d'API dont vous aurez besoin. accès fréquemment. Vous pouvez les mapper ensemble en utilisant Object.keys()
et votre tableau de chaînes, ou consulter la bibliothèque de cartes source de Mozilla sur GitHub, pour des projets plus importants: https://github.com/ mozilla/source-map
dans le cadre de ECMAScript 6
, vous pouvez utiliser la méthode Function.name
function doSomething() {}
alert(doSomething.name); // alerts "doSomething"
Vous pouvez utiliser le nom du constructeur comme:
{your_function}.prototype.constructor.name
ce code retourne simplement le nom d'une méthode.
Vous pouvez l'utiliser, mais ce n'est pas pour tous les navigateurs, seulement ceux qui supportent Error.stack
function VamosRafa(){
var a = new Error().stack.match(/at (.*?) /);
console.log(a[1]);
}
VamosRafa();
Bien sûr, cela s’applique à la fonction actuelle, mais vous voyez l’idée.
À votre santé!
Je sais que c’est une vieille question, mais dernièrement, j’ai rencontré un problème similaire en essayant de décorer certaines méthodes de React Component, à des fins de débogage. Comme on l'a déjà dit, arguments.caller
et arguments.callee
sont interdits en mode strict, ce qui est probablement activé par défaut dans votre React transpiling. Vous pouvez le désactiver, ou j'ai pu créer un autre hack, car dans React toutes les fonctions de classe sont nommées, vous pouvez réellement faire ceci:
Component.prototype.componentWillMount = function componentWillMount() {
console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}
Cela a fonctionné pour moi.
function AbstractDomainClass() {
this.className = function() {
if (!this.$className) {
var className = this.constructor.toString();
className = className.substr('function '.length);
className = className.substr(0, className.indexOf('('));
this.$className = className;
}
return this.$className;
}
}
Code de test:
var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');
J'ai eu un problème similaire et je l'ai résolu comme suit:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace( "function ", "" );
}
Ce code implémente, de manière plus confortable, une réponse que j'ai déjà lue ici au début de cette discussion. Maintenant, j'ai une fonction membre récupérant le nom de n'importe quel objet de fonction. Voici le script complet ...
<script language="javascript" TYPE="text/javascript">
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace("function ", "" );
}
function call_this( _fn ) { document.write( _fn.myname() ); }
function _yeaaahhh() { /* do something */ }
call_this( _yeaaahhh );
</script>
Si j'ai compris ce que vous vouliez faire, c'est ce que je fais dans un constructeur de fonctions.
if (!(this instanceof arguments.callee)) {
throw "ReferenceError: " + arguments.callee.name + " is not defined";
}
Cela fonctionnera dans ES5, ES6, tous les navigateurs et les fonctions du mode strict.
Voici à quoi ça ressemble avec une fonction nommée.
(function myName() {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)
Voici à quoi ça ressemble avec une fonction anonyme.
(() => {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15