Is there a way to get the function parameter names of a function dynamically?
Let’s say my function looks like this:
function doSomething(param1, par
Note: if you want to use ES6 parameter destructuring with the top solution add the following line.
if (result[0] === '{' && result[result.length - 1 === '}']) result = result.slice(1, -1)
How I typically do it:
function name(arg1, arg2){
var args = arguments; // array: [arg1, arg2]
var objecArgOne = args[0].one;
}
name({one: "1", two: "2"}, "string");
You can even ref the args by the functions name like:
name.arguments;
Hope this helps!
//See this:
// global var, naming bB
var bB = 5;
// Dependency Injection cokntroller
var a = function(str, fn) {
//stringify function body
var fnStr = fn.toString();
// Key: get form args to string
var args = fnStr.match(/function\s*\((.*?)\)/);
//
console.log(args);
// if the form arg is 'bB', then exec it, otherwise, do nothing
for (var i = 0; i < args.length; i++) {
if(args[i] == 'bB') {
fn(bB);
}
}
}
// will do nothing
a('sdfdfdfs,', function(some){
alert(some)
});
// will alert 5
a('sdfdsdsfdfsdfdsf,', function(bB){
alert(bB)
});
// see, this shows you how to get function args in string
The answer to this requires 3 steps:
argValues
). This is straight forward as it will be available as arguments
inside the function.argNames
). This not as easy and requires parsing the function. Instead of doing the complex regex yourself and worrying about edge cases (default parameters, comments, ...), you can use a library like babylon that will parse the function into an abstract syntax tree from which you can obtain the names of parameters.The code will be like this
const babylon = require("babylon")
function doSomething(a, b, c) {
// get the values of passed argumenst
const argValues = arguments
// get the names of the arguments by parsing the function
const ast = babylon.parse(doSomething.toString())
const argNames = ast.program.body[0].params.map(node => node.name)
// join the 2 arrays, by looping over the longest of 2 arrays
const maxLen = Math.max(argNames.length, argValues.length)
const args = []
for (i = 0; i < maxLen; i++) {
args.push({name: argNames[i], value: argValues[i]})
}
console.log(args)
// implement the actual function here
}
doSomething(1, 2, 3, 4)
and the logged object will be
[
{
"name": "a",
"value": 1
},
{
"name": "c",
"value": 3
},
{
"value": 4
}
]
And here's a working example https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a
I have read most of the answers here, and I would like to add my one-liner.
new RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)').exec(Function.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '')
or
function getParameters(func) {
return new RegExp('(?:'+func.name+'\\s*|^)\\s*\\((.*?)\\)').exec(func.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '');
}
or for a one-liner function in ECMA6
var getParameters = func => new RegExp('(?:'+func.name+'\\s*|^)\\s*\\((.*?)\\)').exec(func.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '');
__
Let's say you have a function
function foo(abc, def, ghi, jkl) {
//code
}
The below code will return "abc,def,ghi,jkl"
That code will also work with the setup of a function that Camilo Martin gave:
function ( A, b
,c ,d
){}
Also with Bubersson's comment on Jack Allan's answer:
function(a /* fooled you)*/,b){}
__
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
This creates a Regular Expression with the new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
. I have to use new RegExp
because I am injecting a variable (Function.name
, the name of the function being targeted) into the RegExp.
Example If the function name is "foo" (function foo()
), the RegExp will be /foo\s*\((.*?)\)/
.
Function.toString().replace(/\n/g, '')
Then it converts the entire function into a string, and removes all newlines. Removing newlines helps with the function setup Camilo Martin gave.
.exec(...)[1]
This is the RegExp.prototype.exec function. It basically matches the Regular Exponent (new RegExp()
) into the String (Function.toString()
). Then the [1]
will return the first Capture Group found in the Regular Exponent ((.*?)
).
.replace(/\/\*.*?\*\//g, '').replace(/ /g, '')
This will remove every comment inside /*
and */
, and remove all spaces.
This also now supports reading and understanding arrow (=>
) functions, such as f = (a, b) => void 0;
, in which Function.toString()
would return (a, b) => void 0
instead of the normal function's function f(a, b) { return void 0; }
. The original regular expression would have thrown an error in its confusion, but is now accounted for.
The change was from new RegExp(Function.name+'\\s*\\((.*?)\\)')
(/Function\s*\((.*?)\)/
) to new RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)')
(/(?:Function\s*|^)\((.*?)\)/
)
If you want to make all the parameters into an Array instead of a String separated by commas, at the end just add .split(',')
.
The proper way to do this is to use a JS parser. Here is an example using acorn.
const acorn = require('acorn');
function f(a, b, c) {
// ...
}
const argNames = acorn.parse(f).body[0].params.map(x => x.name);
console.log(argNames); // Output: [ 'a', 'b', 'c' ]
The code here finds the names of the three (formal) parameters of the function f
. It does so by feeding f
into acorn.parse()
.