是否有一种方法可以动态地获取函数的函数参数名?
假设我的函数是这样的
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 $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>
其他回答
函数参数字符串值图像动态从JSON。因为项目。product_image2是一个URL字符串,当你在参数内部调用changeImage时,你需要把它放在引号中。
我的功能
items+='<img src='+item.product_image1+' id="saleDetailDivGetImg">';
items+="<img src="+item.product_image2+" onclick='changeImage(\""+item.product_image2+"\");'>";
我的函数
<script type="text/javascript">
function changeImage(img)
{
document.getElementById("saleDetailDivGetImg").src=img;
alert(img);
}
</script>
我修改了来自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 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”,这一点用都没有。
你可以使用"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技巧,它甚至不处理整个字符串。