can anyone help me on how to retrieve function parameter names? For example:
var A = function(a, b, c) {};
I need to get the parameter names outside the function, which is a, b, and c (as in literally as strings, such as to be put in an array ["a", "b", "c"]), so I can validate not only object/class properties in a class towards an interface, but also the parameters.
Before this question starts raising confusion, let me explain about interface implementation in my term and the reason why I need the answer of the question above:
First of all, I found one interesting way I would like to use in implementing interface by Glen Ford in JavaScript:
for (var member in theInterface) {
if ( (typeof theObject[member] != typeof theInterface[member]) ) {
alert("object failed to implement interface member " + member);
return false;
}
}
(Please see the detail about the implementation from ).
However, the implementation above only validates the object properties (variable and methods) only, which is not enough for me.
I need more validation to parameter level, so that the code that implements one interface should follow the interface methods and also follow the parameters from the interface methods as well.
PS. Please don't argue about why use interface or why it's useless or useful; instead it's most useful if you can provide better interface implementation. The focus here is I just need to know how to get function parameter names.
can anyone help me on how to retrieve function parameter names? For example:
var A = function(a, b, c) {};
I need to get the parameter names outside the function, which is a, b, and c (as in literally as strings, such as to be put in an array ["a", "b", "c"]), so I can validate not only object/class properties in a class towards an interface, but also the parameters.
Before this question starts raising confusion, let me explain about interface implementation in my term and the reason why I need the answer of the question above:
First of all, I found one interesting way I would like to use in implementing interface by Glen Ford in JavaScript:
for (var member in theInterface) {
if ( (typeof theObject[member] != typeof theInterface[member]) ) {
alert("object failed to implement interface member " + member);
return false;
}
}
(Please see the detail about the implementation from http://knol.google.com/k/programming-to-the-interface-in-javascript-yes-it-can-be-done-er-i-mean-faked#).
However, the implementation above only validates the object properties (variable and methods) only, which is not enough for me.
I need more validation to parameter level, so that the code that implements one interface should follow the interface methods and also follow the parameters from the interface methods as well.
PS. Please don't argue about why use interface or why it's useless or useful; instead it's most useful if you can provide better interface implementation. The focus here is I just need to know how to get function parameter names.
Share Improve this question edited Feb 1, 2012 at 13:28 asked Feb 1, 2012 at 6:40 user905864user905864 4- This is an unclear question... what is a "parameter name"? You already declare your parameters to your function as "a" "b" and "c"... Can you clarify? Also, what do you mean by "validation"? Are you just looking for a way to validate the incoming parameters in multiple classes? If so, my first inclination would be to create a superclass or something to do the validation for all subclasses... – Jesse Fulton Commented Feb 1, 2012 at 6:47
- Basically, JavaScript isn't type-safe - but it sounds like that's what you want? – Jesse Fulton Commented Feb 1, 2012 at 6:48
- Hi Jesse, yes I've declared my parameters in the function as a, b, and c. But I need to get them (as in, literally take them as string, like ["a", "b", "c"]) so I can use these names for a further interface implementations. I need to "validate" my object properties to be the same as the interface object properties. If you've tried the interface implementation in the link I've provided, maybe you'll get the sense of what I mean. In the link, it only "validates" the object members towards the interface members, however, I need deeper, which also towards the interface members' parameter as well. – user905864 Commented Feb 1, 2012 at 7:01
- 1 Possible duplicate: stackoverflow.com/questions/1007981/… – Anderson Green Commented Apr 24, 2013 at 16:57
6 Answers
Reset to default 12I doubt that there is any decent way to this, in javascript parameter values can be of different type when passed, the types doesn't matter but the order thus.
This might not be the answer that you are looking for but this could help at least.
function test(a,b,c,d) {
}
//this will give us the number of parameters defined in the a function.
confirm(test.length);
To really know the names you can parse the function definition
var str = window['test'].toString();
//str will be "function test(a,b,c,d){}"
Below is a simple parsing test I made:
function test(a,b,c,d)
{
}
var b = function(x,y, z){};
alert(getFnParamNames(b).join(","));
alert(getFnParamNames(test).join(","));
function getFnParamNames(fn){
var fstr = fn.toString();
return fstr.match(/\(.*?\)/)[0].replace(/[()]/gi,'').replace(/\s/gi,'').split(',');
}
The only way would be to retrieve the function as a string and use a RegExp
to get the parameter names:
function test(a,b,c){/*function body*/}
//=> this should return 'a,b,c':
test.toString().replace(/(function.+\()(.+(?=\)))(.+$)/,'$2');
You can use either a regex such as described in here, another alternative would be to use a tokenizer. The following code uses the acorn
javascript parser for checking if a function contains a specific argument name:
function isFunction(value) {
return value && typeof value === 'function';
}
function hasArgument(func, name) {
if (!isFunction(func) || !name) {
return false;
}
var tokenizer = acorn.tokenize(func);
var token = tokenizer();
while (token.type.type !== 'eof') {
// ')' closes function, we do not want to look inside the function body
if (token.type.type === ')') {
return false;
}
if (token.type.type === 'name' && token.value === name) {
return true;
}
token = tokenizer();
}
return false;
}
Just to make complete @jerjer answer, We may also ensure there is at least one match:
function getFnParamNames(fn){
const match = fn.toString().match(/\(.*?\)/)
return match ? match[0].replace(/[()]/gi,'').replace(/\s/gi,'').split(',') : [];
}
Now it's 2018 so may I add a solution that supports arrow function
/**
* (Function) => String[]
*/
function getFnParamNames(fn){
const fnStr = fn.toString()
const arrowMatch = fnStr.match(/\(?[^]*?\)?\s*=>/)
if (arrowMatch) return arrowMatch[0].replace(/[()\s]/gi,'').replace('=>','').split(',')
const match = fnStr.match(/\([^]*?\)/)
return match ? match[0].replace(/[()\s]/gi,'').split(',') : []
}
Note:
[^]
matches all kinds of characters including new line (while .
excludes new line). Source RegExp Documentation
*?
non-greedy quantifier. More explanation here
Tested cases:
console.log(getFnParamNames(name => {
}))
console.log(getFnParamNames(name=>{
}))
console.log(getFnParamNames((name) => {
}))
console.log(getFnParamNames((name, age, ...args) => {
}))
console.log(getFnParamNames((name,age,...args)=>{
}))
console.log(getFnParamNames(function(name,age,...args){
}))
console.log(getFnParamNames(function (name , age , ...args ) {
}))
console.log(getFnParamNames(function(
name,
age,
...args){
}))
console.log(getFnParamNames(new Function('name', 'age' , '...args', 'console.log(args.length)' )))
Actually, regex is not sufficient and robust enough for this task, the easiest way is using a library such as @plumier/reflect
.
https://www.npmjs.com/package/@plumier/reflect
Its a mature reflection library currently used by several library and frameworks and some companies.