是否有一种方法可以动态地获取函数的函数参数名?
假设我的函数是这样的
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
}
现在,我如何从函数内部获得参数名称及其值的列表到数组中?
当前回答
我通常是怎么做的:
function name(arg1, arg2){
var args = arguments; // array: [arg1, arg2]
var objecArgOne = args[0].one;
}
name({one: "1", two: "2"}, "string");
你甚至可以通过函数名引用参数,比如:
name.arguments;
希望这能有所帮助!
其他回答
我已经阅读了这里的大部分答案,我想加上我的一句话。
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, '');
}
或ECMA6中的单行函数
var getParameters = func => new RegExp('(?:'+func.name+'\\s*|^)\\s*\\((.*?)\\)').exec(func.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '');
__
假设有一个函数
function foo(abc, def, ghi, jkl) {
//code
}
下面的代码将返回"abc,def,ghi,jkl"
该代码也将与Camilo Martin给出的一个函数的设置一起工作:
function ( A, b
,c ,d
){}
还有Bubersson对Jack Allan的回答的评论:
function(a /* fooled you)*/,b){}
__
解释
新RegExp (' (?: + Function.name + \ \年代* | ^)\ \ s *\\((.*?)\\)')
这将创建一个正则表达式与新的正则表达式((?:' + Function.name + ' \ \ s * | ^) \ \ s *\\((.*?)\\)').我必须使用新的RegExp,因为我将一个变量(function .name,目标函数的名称)注入到RegExp中。
如果函数名是"foo" (function foo()), RegExp将是/foo\s*\((.*?)\)/。
Function.toString()。替换(\ n / g,”)
然后它将整个函数转换为一个字符串,并删除所有换行符。删除换行符有助于Camilo Martin给出的函数设置。
.exec(…)[1]
这是RegExp.prototype.exec函数。它基本上将正则指数(new RegExp())匹配到字符串(Function.toString())中。然后[1]将返回正则指数((.*?))中找到的第一个捕获组。
.replace (/ \ / \ * . * ?\ \ * / / g,”)。Replace (/ /g, ")
这将删除/*和*/内的所有注释,并删除所有空格。
这现在也支持读取和理解箭头(=>)函数,如f = (a, b) => void 0;,其中function . tostring()将返回(a, b) => void 0,而不是普通函数的函数f(a, b){返回void 0;}。原来的正则表达式会在混乱中抛出一个错误,但现在已经解决了这个问题。
的变化是新的正则表达式(Function.name + \ \年代 *\\((.*?)\\)') (/ 函数\ s *\((.*?)\)/) 新的正则表达式(’(?:+ Function.name + \ \年代 *|^)\\((.*?)\\)') (/(?: 函数\ s *|^)\((.*?)\)/)
如果你想让所有的参数变成一个数组,而不是一个由逗号分隔的字符串,在最后添加.split(',')。
我知道这是一个老问题,但初学者一直在复制从函数的字符串表示中提取参数名的解决方案,就好像这是任何代码中的良好实践一样。大多数情况下,这只是隐藏了逻辑中的缺陷。
在函数声明的圆括号中写入参数名可以看作是创建变量的一种简写语法。这样的:
function doSomething(foo, bar) {
console.log("does something");
}
...类似于这个:
function doSomething() {
var foo = arguments[0];
var bar = arguments[1];
console.log("does something");
}
变量本身存储在函数的作用域中,而不是作为对象中的属性。就像您不能用代码操作变量的名称一样,也无法检索参数的名称,因为它不是字符串,并且可以在JIT编译期间消除它。
我一直认为函数的字符串表示形式是调试目的的工具,特别是因为这个参数类数组对象。首先,您不需要为参数指定名称。如果您尝试解析一个字符串化函数,它实际上不会告诉您它可能接受的额外未命名参数。
还有一种更糟糕、更常见的情况。如果一个函数有超过3或4个参数,那么向它传递一个更容易处理的对象可能是合乎逻辑的。
function saySomething(obj) {
if(obj.message) console.log((obj.sender || "Anon") + ": " + obj.message);
}
saySomething({sender: "user123", message: "Hello world"});
在这种情况下,函数本身将能够读取它接收到的对象,并查找其属性并获得它们的名称和值,但试图解析函数的字符串表示只能为参数提供“obj”,这一点用都没有。
我不知道如何得到参数列表但是你可以这样做来得到它期望的数量。注意,这只计算签名中没有默认值的参数:
函数foobar(a, b, c) {} 函数foobar2(a, b=false, c=false) {} console.log (foobar.length);//打印3个 console.log (foobar2.length);//打印1个
尝试手动:
function something(arg1, arg2) {
console.log ( arg1 + arg2 );
}
下面是一个更新的解决方案,试图以一种紧凑的方式解决上述所有边缘情况:
function $args(func) {
return (func + '')
.replace(/[/][/].*$/mg,'') // strip single-line comments
.replace(/\s+/g, '') // strip white space
.replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments
.split('){', 1)[0].replace(/^[^(]*[(]/, '') // extract the parameters
.replace(/=[^,]+/g, '') // strip any ES6 defaults
.split(',').filter(Boolean); // split & filter [""]
}
简化的测试输出(完整的测试用例附在下面):
'function (a,b,c)...' // returns ["a","b","c"]
'function ()...' // returns []
'function named(a, b, c) ...' // returns ["a","b","c"]
'function (a /* = 1 */, b /* = true */) ...' // returns ["a","b"]
'function fprintf(handle, fmt /*, ...*/) ...' // returns ["handle","fmt"]
'function( a, b = 1, c )...' // returns ["a","b","c"]
'function (a=4*(5/3), b) ...' // returns ["a","b"]
'function (a, // single-line comment xjunk) ...' // returns ["a","b"]
'function (a /* fooled you...' // returns ["a","b"]
'function (a /* function() yes */, \n /* no, */b)/* omg! */...' // returns ["a","b"]
'function ( A, b \n,c ,d \n ) \n ...' // returns ["A","b","c","d"]
'function (a,b)...' // returns ["a","b"]
'function $args(func) ...' // returns ["func"]
'null...' // returns ["null"]
'function Object() ...' // returns []
function $args(func) { return (func + '') .replace(/[/][/].*$/mg,'') // strip single-line comments .replace(/\s+/g, '') // strip white space .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments .split('){', 1)[0].replace(/^[^(]*[(]/, '') // extract the parameters .replace(/=[^,]+/g, '') // strip any ES6 defaults .split(',').filter(Boolean); // split & filter [""] } // test cases document.getElementById('console_info').innerHTML = ( [ // formatting -- typical function(a,b,c){}, function(){}, function named(a, b, c) { /* multiline body */ }, // default values -- conventional function(a /* = 1 */, b /* = true */) { a = a||1; b=b||true; }, function fprintf(handle, fmt /*, ...*/) { }, // default values -- ES6 "function( a, b = 1, c ){}", "function (a=4*(5/3), b) {}", // embedded comments -- sardonic function(a, // single-line comment xjunk) {} b //,c,d ) // single-line comment {}, function(a /* fooled you{*/,b){}, function /* are you kidding me? (){} */(a /* function() yes */, /* no, */b)/* omg! */{/*}}*/}, // formatting -- sardonic function ( A, b ,c ,d ) { }, // by reference this.jQuery || function (a,b){return new e.fn.init(a,b,h)}, $args, // inadvertent non-function values null, Object ].map(function(f) { var abbr = (f + '').replace(/\n/g, '\\n').replace(/\s+|[{]+$/g, ' ').split("{", 1)[0] + "..."; return " '" + abbr + "' // returns " + JSON.stringify($args(f)); }).join("\n") + "\n"); // output for copy and paste as a markdown snippet <pre id='console_info'></pre>