是否有一种方法可以动态地获取函数的函数参数名?
假设我的函数是这样的
function doSomething(param1, param2, .... paramN){
// fill an array with the parameter name and value
// some other code
}
现在,我如何从函数内部获得参数名称及其值的列表到数组中?
是否有一种方法可以动态地获取函数的函数参数名?
假设我的函数是这样的
function doSomething(param1, param2, .... paramN){
// fill an array with the parameter name and value
// some other code
}
现在,我如何从函数内部获得参数名称及其值的列表到数组中?
当前回答
下面的函数将返回传入的任何函数的参数名称的数组。
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if(result === null)
result = [];
return result;
}
使用示例:
getParamNames(getParamNames) // returns ['func']
getParamNames(function (a,b,c,d){}) // returns ['a','b','c','d']
getParamNames(function (a,/*b,c,*/d){}) // returns ['a','d']
getParamNames(function (){}) // returns []
编辑:
随着ES6的发明,这个函数可以被默认参数绊倒。这里有一个在大多数情况下都有效的快速技巧:
var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
我说大多数情况是因为有些事情会出错
function (a=4*(5/3), b) {} // returns ['a']
编辑: 我还注意到vikasde也想要数组中的参数值。这已经在名为arguments的局部变量中提供了。
节选自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments:
arguments对象不是数组。它类似于Array,但除了长度之外没有任何Array属性。例如,它没有pop方法。然而,它可以转换为一个真正的数组:
var args = Array.prototype.slice.call(arguments);
如果Array泛型可用,则可以使用以下方法:
var args = Array.slice(arguments);
其他回答
你可以使用"arguments"属性访问传递给函数的参数值。
function doSomething()
{
var args = doSomething.arguments;
var numArgs = args.length;
for(var i = 0 ; i < numArgs ; i++)
{
console.log("arg " + (i+1) + " = " + args[i]);
//console.log works with firefox + firebug
// you can use an alert to check in other browsers
}
}
doSomething(1, '2', {A:2}, [1,2,3]);
无论哪种解决方案,它都不能破坏奇怪的函数,其toString()看起来也很奇怪:
function ( A, b
,c ,d
){}
另外,为什么要使用复杂的正则表达式?可以这样做:
function getArguments(f) {
return f.toString().split(')',1)[0].replace(/\s/g,'').substr(9).split(',');
}
这适用于每个函数,唯一的正则表达式是删除空白,由于.split技巧,它甚至不处理整个字符串。
我想建议解决方案,支持箭头函数像 我将本文用于基本正则表达式和https://davidwalsh.name/javascript-arguments,并添加了箭头函数支持
(arg1,arg2) => {}
or
arg => {}
function getArgs(func) {
if(func.length === 0){
return []
}
let string = func.toString();
let args;
// First match everything inside the function argument parens. like `function (arg1,arg2) {}` or `async function(arg1,arg2) {}
args = string.match(/(?:async|function)\s*.*?\(([^)]*)\)/)?.[1] ||
// arrow functions with multiple arguments like `(arg1,arg2) => {}`
string.match(/^\s*\(([^)]*)\)\s*=>/)?.[1] ||
// arrow functions with single argument without parens like `arg => {}`
string.match(/^\s*([^=]*)=>/)?.[1]
// Split the arguments string into an array comma delimited.
return args.split(',').map(function(arg) {
// Ensure no inline comments are parsed and trim the whitespace.
return arg.replace(/\/\*.*\*\//, '').trim();
}).filter(function(arg) {
// Ensure no undefined values are added.
return arg;
});
}
我修改了来自AngularJS的版本,它实现了一个依赖注入机制,可以在没有Angular的情况下工作。我还更新了STRIP_COMMENTS正则表达式以配合ECMA6,因此它支持签名中的默认值等内容。
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(.+?)\1\s*$/; var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg; function annotate(fn) { var $inject, fnText, argDecl, last; if (typeof fn == 'function') { if (!($inject = fn.$inject)) { $inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''); argDecl = fnText.match(FN_ARGS); argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) { arg.replace(FN_ARG, function(all, underscore, name) { $inject.push(name); }); }); fn.$inject = $inject; } } else { throw Error("not a function") } return $inject; } console.log("function(a, b)",annotate(function(a, b) { console.log(a, b, c, d) })) console.log("function(a, b = 0, /*c,*/ d)",annotate(function(a, b = 0, /*c,*/ d) { console.log(a, b, c, d) })) annotate({})
尝试手动:
function something(arg1, arg2) {
console.log ( arg1 + arg2 );
}