Existe-t-il un moyen d'obtenir dynamiquement les noms des paramètres de fonction d'une fonction?
Disons que ma fonction ressemble à ceci:
function doSomething(param1, param2, .... paramN){
// fill an array with the parameter name and value
// some other code
}
Maintenant, comment puis-je obtenir une liste des noms de paramètres et de leurs valeurs dans un tableau à l'intérieur de la fonction?
function doSomething(...args) { /*use args*/}
Réponses:
La fonction suivante renverra un tableau des noms de paramètres de toute fonction transmise.
Exemple d'utilisation:
Modifier :
Avec l'invention de l'ES6, cette fonction peut être déclenchée par des paramètres par défaut. Voici un hack rapide qui devrait fonctionner dans la plupart des cas:
Je dis la plupart des cas, car il y a des choses qui vont faire trébucher
Edit : je note également que vikasde veut également les valeurs des paramètres dans un tableau. Ceci est déjà fourni dans une variable locale nommée arguments.
extrait de https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments :
L'objet arguments n'est pas un tableau. Il est similaire à un tableau, mais n'a aucune propriété de tableau à l'exception de la longueur. Par exemple, il n'a pas la méthode pop. Cependant, il peut être converti en un véritable tableau:
Si des génériques de tableau sont disponibles, on peut utiliser les éléments suivants à la place:
la source
var fn = function(a /* fooled you)*/,b){};
entraînera["a", "/*", "fooled", "you"]
Ci-dessous est le code extrait d'AngularJS qui utilise la technique pour son mécanisme d'injection de dépendance.
Et voici une explication tirée de http://docs.angularjs.org/tutorial/step_05
la source
annotate = angular.injector.$$annotate
Voici une solution mise à jour qui tente de résoudre tous les cas marginaux mentionnés ci-dessus de manière compacte:
Sortie de test abrégée (les cas de test complets sont joints ci-dessous):
Afficher l'extrait de code
la source
return (func+'') .replace(/[/][/].*$/mg,'') // strip single-line comments (line-ending sensitive, so goes first) .replace(/\s+/g,'') // remove whitespace
func + ''
parFunction.toString.call(func)
pour vous défendre contre le cas où la fonction a une implémentation .toString () personnalisée..split(/\)[\{=]/, 1)[0]
({ a, b, c })
) en tous les paramètres à l'intérieur de la déstructuration. pour garder les objets déstructurés intacts, changez le dernier.split
en:.split(/,(?![^{]*})/g)
Une solution moins sujette aux erreurs et aux commentaires serait:
la source
Beaucoup de réponses ici utilisent des expressions rationnelles, c'est bien mais cela ne gère pas trop bien les nouveaux ajouts au langage (comme les fonctions fléchées et les classes). Il est également à noter que si vous utilisez l'une de ces fonctions sur du code minifié, cela ira 🔥. Il utilisera le nom minifié. Angular contourne cela en vous permettant de passer dans un tableau ordonné de chaînes qui correspond à l'ordre des arguments lors de leur enregistrement dans le conteneur DI. Ainsi de suite avec la solution:
Cela gère le problème d'analyse d'origine et quelques autres types de fonctions (par exemple les fonctions fléchées). Voici une idée de ce qu'il peut et ne peut pas gérer tel quel:
Selon ce que vous voulez l'utiliser pour les proxys ES6 et la déstructuration peut être votre meilleur pari. Par exemple, si vous souhaitez l'utiliser pour l'injection de dépendances (en utilisant les noms des paramètres), vous pouvez le faire comme suit:
Ce n'est pas le résolveur le plus avancé, mais il donne une idée de la façon dont vous pouvez utiliser un proxy pour le gérer si vous souhaitez utiliser l'analyseur args pour une DI simple. Il y a cependant une légère mise en garde dans cette approche. Nous devons utiliser des affectations de déstructuration au lieu de paramètres normaux. Lorsque nous passons dans le proxy injecteur, la déstructuration équivaut à appeler le getter sur l'objet.
Cela génère les éléments suivants:
Son câblé l'ensemble de l'application. Le meilleur est que l'application est facile à tester (vous pouvez simplement instancier chaque classe et passer dans des mocks / stubs / etc). De plus, si vous devez échanger des implémentations, vous pouvez le faire à partir d'un seul endroit. Tout cela est possible grâce aux objets JS Proxy.
Remarque: il y a beaucoup de travail qui devrait être fait pour cela avant qu'il ne soit prêt pour une utilisation en production, mais cela donne une idée de ce à quoi il ressemblerait.
C'est un peu tard dans la réponse, mais cela peut aider ceux qui pensent à la même chose. 👍
la source
Je sais que c'est une vieille question, mais les débutants ont copié ceci comme si c'était une bonne pratique dans n'importe quel code. La plupart du temps, le fait d'avoir à analyser la représentation sous forme de chaîne d'une fonction pour utiliser ses noms de paramètres masque simplement une faille dans la logique du code.
Les paramètres d'une fonction sont en fait stockés dans un objet de type tableau appelé
arguments
, où le premier argument estarguments[0]
, le second estarguments[1]
et ainsi de suite. L'écriture de noms de paramètres entre parenthèses peut être considérée comme une syntaxe abrégée. Ce:...est le même que:
Les variables elles-mêmes sont stockées dans la portée de la fonction, pas en tant que propriétés dans un objet. Il n'y a aucun moyen de récupérer le nom du paramètre via le code car il s'agit simplement d'un symbole représentant la variable en langage humain.
J'ai toujours considéré la représentation sous forme de chaîne d'une fonction comme un outil de débogage, en particulier à cause de cela
arguments
objet de type tableau. Vous n'êtes pas obligé de donner des noms aux arguments en premier lieu. Si vous essayez d'analyser une fonction stringifiée, elle ne vous indique pas réellement les paramètres supplémentaires non nommés qu'elle pourrait prendre.Voici une situation encore pire et plus courante. Si une fonction a plus de 3 ou 4 arguments, il peut être logique de lui passer un objet à la place, ce qui est plus facile à utiliser.
Dans ce cas, la fonction elle-même pourra lire l'objet qu'elle reçoit et chercher ses propriétés et obtenir à la fois leurs noms et leurs valeurs, mais essayer d'analyser la représentation sous forme de chaîne de la fonction ne vous donnera que "obj" pour les paramètres, ce qui n'est pas du tout utile.
la source
Function.prototype.toString = function () { return 'function () { [native code] }'; };
Proxy
( piège constructeur et piège à appliquer ) etReflection
pour gérer DI pour certains de mes modules. C'est assez solide.Étant donné que JavaScript est un langage de script, je pense que son introspection devrait prendre en charge l'obtention des noms de paramètres de fonction. Se lancer sur cette fonctionnalité est une violation des premiers principes, j'ai donc décidé d'explorer la question plus avant.
Cela m'a amené à cette question, mais pas de solutions intégrées. Ce qui m'a conduit à cette réponse qui explique que
arguments
n'est déprécié qu'en dehors de la fonction, donc on ne peut plus utilisermyFunction.arguments
ou on obtient:Il est temps de retrousser nos manches et de se mettre au travail:
⭐ La récupération des paramètres de fonction nécessite un analyseur car des expressions complexes comme
4*(5/3)
peuvent être utilisées comme valeurs par défaut. Donc , la réponse de Gaafar ou la réponse de James Drew sont jusqu'à présent les meilleures approches.J'ai essayé le babylon et esprima parseurs mais malheureusement ils ne peuvent analyser des fonctions anonymes autonomes, comme en pointe dans la réponse de Mateusz Charytoniuk . J'ai trouvé une autre solution de contournement en entourant le code entre parenthèses, afin de ne pas changer la logique:
Les nouvelles lignes évitent les problèmes avec
//
(commentaires sur une seule ligne).⭐ Si un analyseur n'est pas disponible, la meilleure option suivante consiste à utiliser une technique éprouvée comme les expressions régulières de l'injecteur de dépendance d'Angular.js. J'ai combiné une version fonctionnelle de la réponse de Lambder avec Lambder humbletim et ajouté un
ARROW
booléen facultatif pour contrôler si les fonctions de flèche de graisse ES6 sont autorisées par les expressions régulières.Voici deux solutions que j'ai mises en place. Notez que ceux-ci n'ont pas de logique pour détecter si une fonction a une syntaxe valide, ils extraient uniquement les arguments. Ceci est généralement correct car nous passons généralement des fonctions analysées à
getArguments()
leur syntaxe est donc déjà valide.Je vais essayer de gérer ces solutions du mieux que je peux, mais sans effort des responsables JavaScript, cela restera un problème ouvert.
Version Node.js (non exécutable tant que StackOverflow ne prend pas en charge Node.js):
Exemple de travail complet:
https://repl.it/repls/SandybrownPhonyAngles
Version du navigateur (notez qu'elle s'arrête à la première valeur par défaut complexe):
Exemple de travail complet:
https://repl.it/repls/StupendousShowyOffices
la source
J'ai lu la plupart des réponses ici, et je voudrais ajouter mon one-liner.
ou
ou pour une fonction monoligne dans ECMA6
__
Disons que vous avez une fonction
Le code ci-dessous sera de retour
"abc,def,ghi,jkl"
Ce code fonctionnera également avec la configuration d'une fonction que Camilo Martin a donnée:
Aussi avec le commentaire de Bubersson sur la réponse de Jack Allan :
__
Explication
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
Cela crée une expression régulière avec le
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
. Je dois utilisernew RegExp
car j'injecte une variable (Function.name
, le nom de la fonction ciblée) dans RegExp.Exemple Si le nom de la fonction est "foo" (
function foo()
), le RegExp le sera/foo\s*\((.*?)\)/
.Function.toString().replace(/\n/g, '')
Il convertit ensuite la fonction entière en chaîne et supprime tous les retours à la ligne. La suppression des sauts de ligne aide à la configuration des fonctions de Camilo Martin .
.exec(...)[1]
Telle est la
RegExp.prototype.exec
fonction. Il correspond essentiellement à l'exposant régulier (new RegExp()
) dans la chaîne (Function.toString()
). Ensuite, le[1]
retournera le premier groupe de capture trouvé dans l'exposant régulier ((.*?)
)..replace(/\/\*.*?\*\//g, '').replace(/ /g, '')
Cela supprimera tous les commentaires à l'intérieur
/*
et*/
, et supprimera tous les espaces.Cela prend également en charge la lecture et la compréhension des fonctions de flèche (
=>
), telles quef = (a, b) => void 0;
, dans lesquellesFunction.toString()
retournerait(a, b) => void 0
au lieu des fonctions normalesfunction f(a, b) { return void 0; }
. L'expression régulière d'origine aurait jeté une erreur dans sa confusion, mais est maintenant prise en compte.Le changement est passé de
new RegExp(Function.name+'\\s*\\((.*?)\\)')
(/Function\s*\((.*?)\)/
) ànew RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)')
(/(?:Function\s*|^)\((.*?)\)/
)Si vous souhaitez transformer tous les paramètres en un tableau au lieu d'une chaîne séparée par des virgules, ajoutez simplement à la fin
.split(',')
.la source
f = (a, b) => void 0
; surgetParameters(f)
je reçoisTypeError: Cannot read property '1' of null
getParameters(a => b => c => d => a*b*c*d)
, qui , avec votre code donne encore queTypeError: Cannot read property '1' of null
... alors que celui - ci fonctionne stackoverflow.com/a/29123804=> ["a", "b", "c"]
la source
Vous pouvez également utiliser l'analyseur "esprima" pour éviter de nombreux problèmes avec les commentaires, les espaces et autres choses dans la liste des paramètres.
Cela fonctionne même avec du code comme celui-ci:
la source
J'ai essayé de le faire auparavant, mais je n'ai jamais trouvé de moyen pratique de le faire. J'ai fini par passer un objet à la place, puis en le parcourant.
la source
Je ne sais pas si cette solution convient à votre problème, mais elle vous permet de redéfinir la fonction que vous souhaitez, sans avoir à changer le code qui l'utilise. Les appels existants utiliseront des paramètres positionnés, tandis que l'implémentation de la fonction peut utiliser des "paramètres nommés" (un seul paramètre de hachage).
Je pensais que vous modifieriez de toute façon les définitions de fonctions existantes, alors pourquoi ne pas avoir une fonction d'usine qui fait exactement ce que vous voulez:
J'espère que ça aide.
la source
La bonne façon de procéder consiste à utiliser un analyseur JS. Voici un exemple utilisant du gland .
Le code trouve ici les noms des trois paramètres (formels) de la fonction
f
. Il le fait par l' alimentationf
enacorn.parse()
.la source
Je ne sais pas comment obtenir une liste des paramètres mais vous pouvez le faire pour obtenir combien il attend.
la source
function gotcha (a, b = false, c) {}; alert(gotcha.length)
En prenant la réponse de @ jack-allan, j'ai légèrement modifié la fonction pour autoriser les propriétés par défaut d'ES6 telles que:
revenir encore
[ 'a', 'b' ]
la source
Comment je le fais généralement:
Vous pouvez même référencer les arguments par le nom des fonctions comme:
J'espère que cela t'aides!
la source
var args = name.arguments; console.log('I WANNa SEE', args);
sortir quelque chose comme "{arg1: {...}, arg2: 'string'}"? Cela pourrait éclaircir les choses:(function fn (arg, argg, arrrrgggg) { console.log('#fn:', fn.arguments, Object.keys(fn.arguments)); }); fn('Huh...?', 'Wha...?', 'Magic...?');
. Les arguments de fonction sont un objet de type «tableau», ayant des indices énumérables. Je ne pense pas qu'un mappage de hachage soit possible, mais vous pouvez simplement passer un littéral objet dans lequel est une bonne pratique si vous avez de toute façon plus de 4 paramètres.la source
La réponse à cela nécessite 3 étapes:
argValues
). C'est simple car il sera disponible enarguments
dans la fonction.argNames
). Ce n'est pas aussi facile et nécessite l'analyse de la fonction. Au lieu de faire vous-même le regex complexe et de vous soucier des cas marginaux (paramètres par défaut, commentaires, ...), vous pouvez utiliser une bibliothèque comme babylon qui analysera la fonction dans une arborescence de syntaxe abstraite à partir de laquelle vous pouvez obtenir les noms des paramètres.Le code sera comme ça
et l'objet enregistré sera
Et voici un exemple de travail https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a
la source
la source
Wow déjà tant de réponses .. Im assez sûr que cela soit enterré. Même si je pensais que cela pourrait être utile pour certains.
Je n'étais pas entièrement satisfait des réponses choisies car dans ES6 cela ne fonctionne pas bien avec les valeurs par défaut. Et il ne fournit pas non plus les informations de valeur par défaut. Je voulais également une fonction légère qui ne dépende pas d'une bibliothèque externe.
Cette fonction est très utile à des fins de débogage, par exemple: la journalisation de la fonction appelée avec ses paramètres, les valeurs des paramètres par défaut et les arguments.
J'ai passé un peu de temps là-dessus hier, à trouver le bon RegExp pour résoudre ce problème et c'est ce que j'ai trouvé. Cela fonctionne très bien et je suis très satisfait du résultat:
Comme vous pouvez le constater, certains noms de paramètres disparaissent car le transpilateur Babel les supprime de la fonction. Si vous l'exécutiez dans le dernier NodeJS, cela fonctionne comme prévu (les résultats commentés proviennent de NodeJS).
Une autre remarque, comme indiqué dans le commentaire, est que cela ne fonctionne pas avec les fonctions de flèche en ligne comme valeur par défaut. Cela rend tout simplement compliqué l'extraction des valeurs à l'aide d'un RegExp.
Veuillez me faire savoir si cela vous a été utile! J'adorerais entendre des commentaires!
la source
Je vais vous donner un court exemple ci-dessous:
la source
Ce package utilise une refonte afin de créer un AST, puis les noms des paramètres sont collectés à partir de leur, ce qui lui permet de prendre en charge la correspondance de modèles, les arguments par défaut, les fonctions fléchées et d'autres fonctionnalités ES6.
https://www.npmjs.com/package/es-arguments
la source
J'ai modifié la version tirée d' AngularJS qui implémente un mécanisme d'injection de dépendances pour fonctionner sans Angular. J'ai également mis à jour l'
STRIP_COMMENTS
expression régulière pour qu'elle fonctionneECMA6
, elle prend donc en charge des éléments tels que les valeurs par défaut dans la signature.la source
Vous pouvez accéder aux valeurs d'argument transmises à une fonction à l'aide de la propriété "arguments".
la source
arguments
propriété d'une instance de fonction est obsolète. Voir developer.mozilla.org/en/Core_JavaScript_1.5_Reference/…C'est assez simple.
Au début, il y a une obsolète
arguments.callee
- une référence à la fonction appelée. Au second, si vous avez une référence à votre fonction, vous pouvez facilement obtenir leur représentation textuelle. Au troisième, si vous appelez votre fonction en tant que constructeur, vous pouvez également avoir un lien via yourObject.constructor. NB: La première solution est obsolète, donc si vous ne pouvez pas ne pas l'utiliser, vous devez également penser à l'architecture de votre application. Si vous n'avez pas besoin de noms de variables exacts, utilisez simplement une variable interne de fonctionarguments
sans aucune magie.https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee
Tous vont appeler toString et remplacer par re afin que nous puissions créer un assistant:
Quelques exemples:
Profitez avec JS!
UPD: Jack Allan a été fourni une solution un peu meilleure en fait. GJ Jack!
la source
SomeFuncName
place dearguments.callee
(les deux pointent vers l'objet fonction lui-même).Quelle que soit la solution, elle ne doit pas casser les fonctions bizarres, dont l'
toString()
apparence est tout aussi bizarre:Aussi, pourquoi utiliser des expressions régulières complexes? Cela peut se faire comme:
Cela fonctionne partout avec chaque fonction, et le seul regex est la suppression des espaces blancs qui ne traite même pas la chaîne entière en raison de l'
.split
astuce.la source
Ok donc une vieille question avec plein de réponses adéquates. voici mon offre qui n'utilise pas l'expression régulière, à l'exception de la tâche subalterne de dépouiller les espaces. (Je dois noter que la fonction "strips_comments" les espace en fait, plutôt que de les supprimer physiquement. C'est parce que je l'utilise ailleurs et pour diverses raisons, j'ai besoin que les emplacements des jetons non-commentaires d'origine restent intacts)
C'est un bloc de code assez long car ce collage comprend un mini framework de test.
la source
Voici une façon:
Remarque: cela ne fonctionne que sur les navigateurs qui prennent en charge
arguments.callee
.la source
Remarque: si vous souhaitez utiliser la déstructuration des paramètres ES6 avec la solution supérieure, ajoutez la ligne suivante.
la source
fonction paramètre chaîne valeur image dynamiquement à partir de JSON . Étant donné que item.product_image2 est une chaîne d'URL, vous devez la mettre entre guillemets lorsque vous appelez changeImage à l'intérieur du paramètre.
Ma fonction Onclick
Ma fonction
la source