Da es sich bei JavaScript um eine Skriptsprache handelt, sollte die Introspektion meines Erachtens die Ermittlung von Funktionsparameternamen unterstützen. Der Verzicht auf diese Funktionalität ist ein Verstoß gegen die ersten Prinzipien, also habe ich beschlossen, das Problem weiter zu untersuchen.
Das führte mich zu diese Frage aber keine eingebauten Lösungen. Das führte mich zu diese Antwort die erklärt, dass arguments
ist nur veraltet außerhalb die Funktion, also können wir nicht mehr myFunction.arguments
oder wir bekommen:
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
Zeit, die Ärmel hochzukrempeln und an die Arbeit zu gehen:
Das Abrufen von Funktionsparametern erfordert einen Parser, da komplexe Ausdrücke wie 4*(5/3)
können als Standardwerte verwendet werden. Also Gaafar's Antwort o James Drews Antwort sind bis jetzt die besten Ansätze.
Ich habe die babylon y esprima Parser, aber leider können sie keine eigenständigen anonymen Funktionen parsen, wie es in Antwort von Mateusz Charytoniuk . Ich habe jedoch eine andere Lösung gefunden, indem ich den Code in Klammern gesetzt habe, um die Logik nicht zu verändern:
const ast = parser.parse("(\n" + func.toString() + "\n)")
Die Zeilenumbrüche verhindern Probleme mit //
(einzeilige Kommentare).
Wenn kein Parser zur Verfügung steht, ist die nächstbeste Option die Verwendung einer bewährten Technik wie die regulären Ausdrücke des Dependency Injectors von Angular.js. Ich habe eine funktionale Version von Antwort von Lambder con humbletim's Antwort und fügte eine optionale ARROW
Boolescher Wert zur Kontrolle, ob ES6-Fettpfeilfunktionen von den regulären Ausdrücken zugelassen werden.
Hier sind zwei Lösungen, die ich zusammengestellt habe. Beachten Sie, dass diese keine Logik haben, um zu erkennen, ob eine Funktion eine gültige Syntax hat, sie extrahieren nur die Argumente. Das ist im Allgemeinen in Ordnung, da wir normalerweise geparste Funktionen an getArguments()
ihre Syntax ist also bereits gültig.
Ich werde versuchen, diese Lösungen so gut wie möglich zu kuratieren, aber ohne die Bemühungen der JavaScript-Maintainer wird dies ein offenes Problem bleiben.
Node.js-Version (nicht lauffähig, bis StackOverflow Node.js unterstützt):
const parserName = 'babylon';
// const parserName = 'esprima';
const parser = require(parserName);
function getArguments(func) {
const maybe = function (x) {
return x || {}; // optionals support
}
try {
const ast = parser.parse("(\n" + func.toString() + "\n)");
const program = parserName == 'babylon' ? ast.program : ast;
return program
.body[0]
.expression
.params
.map(function(node) {
return node.name || maybe(node.left).name || '...' + maybe(node.argument).name;
});
} catch (e) {
return []; // could also return null
}
};
////////// TESTS //////////
function logArgs(func) {
let object = {};
object[func] = getArguments(func);
console.log(object);
// console.log(/*JSON.stringify(*/getArguments(func)/*)*/);
}
console.log('');
console.log('////////// MISC //////////');
logArgs((a, b) => {});
logArgs((a, b = 1) => {});
logArgs((a, b, ...args) => {});
logArgs(function(a, b, ...args) {});
logArgs(function(a, b = 1, c = 4 * (5 / 3), d = 2) {});
logArgs(async function(a, b, ...args) {});
logArgs(function async(a, b, ...args) {});
console.log('');
console.log('////////// FUNCTIONS //////////');
logArgs(function(a, b, c) {});
logArgs(function() {});
logArgs(function named(a, b, c) {});
logArgs(function(a /* = 1 */, b /* = true */) {});
logArgs(function fprintf(handle, fmt /*, ...*/) {});
logArgs(function(a, b = 1, c) {});
logArgs(function(a = 4 * (5 / 3), b) {});
// logArgs(function (a, // single-line comment xjunk) {});
// logArgs(function (a /* fooled you {});
// logArgs(function (a /* function() yes */, \n /* no, */b)/* omg! */ {});
// logArgs(function ( A, b \n,c ,d \n ) \n {});
logArgs(function(a, b) {});
logArgs(function $args(func) {});
logArgs(null);
logArgs(function Object() {});
console.log('');
console.log('////////// STRINGS //////////');
logArgs('function (a,b,c) {}');
logArgs('function () {}');
logArgs('function named(a, b, c) {}');
logArgs('function (a /* = 1 */, b /* = true */) {}');
logArgs('function fprintf(handle, fmt /*, ...*/) {}');
logArgs('function( a, b = 1, c ) {}');
logArgs('function (a=4*(5/3), b) {}');
logArgs('function (a, // single-line comment xjunk) {}');
logArgs('function (a /* fooled you {}');
logArgs('function (a /* function() yes */, \n /* no, */b)/* omg! */ {}');
logArgs('function ( A, b \n,c ,d \n ) \n {}');
logArgs('function (a,b) {}');
logArgs('function $args(func) {}');
logArgs('null');
logArgs('function Object() {}');
Vollständiges Arbeitsbeispiel:
https://repl.it/repls/SandybrownPhonyAngles
Browserversion (beachten Sie, dass sie beim ersten komplexen Standardwert stehen bleibt):
function getArguments(func) {
const ARROW = true;
const FUNC_ARGS = ARROW ? /^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m : /^(function)\s*[^\(]*\(\s*([^\)]*)\)/m;
const FUNC_ARG_SPLIT = /,/;
const FUNC_ARG = /^\s*(_?)(.+?)\1\s*$/;
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
return ((func || '').toString().replace(STRIP_COMMENTS, '').match(FUNC_ARGS) || ['', '', ''])[2]
.split(FUNC_ARG_SPLIT)
.map(function(arg) {
return arg.replace(FUNC_ARG, function(all, underscore, name) {
return name.split('=')[0].trim();
});
})
.filter(String);
}
////////// TESTS //////////
function logArgs(func) {
let object = {};
object[func] = getArguments(func);
console.log(object);
// console.log(/*JSON.stringify(*/getArguments(func)/*)*/);
}
console.log('');
console.log('////////// MISC //////////');
logArgs((a, b) => {});
logArgs((a, b = 1) => {});
logArgs((a, b, ...args) => {});
logArgs(function(a, b, ...args) {});
logArgs(function(a, b = 1, c = 4 * (5 / 3), d = 2) {});
logArgs(async function(a, b, ...args) {});
logArgs(function async(a, b, ...args) {});
console.log('');
console.log('////////// FUNCTIONS //////////');
logArgs(function(a, b, c) {});
logArgs(function() {});
logArgs(function named(a, b, c) {});
logArgs(function(a /* = 1 */, b /* = true */) {});
logArgs(function fprintf(handle, fmt /*, ...*/) {});
logArgs(function(a, b = 1, c) {});
logArgs(function(a = 4 * (5 / 3), b) {});
// logArgs(function (a, // single-line comment xjunk) {});
// logArgs(function (a /* fooled you {});
// logArgs(function (a /* function() yes */, \n /* no, */b)/* omg! */ {});
// logArgs(function ( A, b \n,c ,d \n ) \n {});
logArgs(function(a, b) {});
logArgs(function $args(func) {});
logArgs(null);
logArgs(function Object() {});
console.log('');
console.log('///////// STRINGS //////////');
logArgs('function (a,b,c) {}');
logArgs('function () {}');
logArgs('function named(a, b, c) {}');
logArgs('function (a /* = 1 */, b /* = true */) {}');
logArgs('function fprintf(handle, fmt /*, ...*/) {}');
logArgs('function( a, b = 1, c ) {}');
logArgs('function (a=4*(5/3), b) {}');
logArgs('function (a, // single-line comment xjunk) {}');
logArgs('function (a /* fooled you {}');
logArgs('function (a /* function() yes */, \n /* no, */b)/* omg! */ {}');
logArgs('function ( A, b \n,c ,d \n ) \n {}');
logArgs('function (a,b) {}');
logArgs('function $args(func) {}');
logArgs('null');
logArgs('function Object() {}');
Vollständiges Arbeitsbeispiel:
https://repl.it/repls/StupendousShowyOffices