如何dynamic获取函数参数名称/值?

有没有办法dynamic获取函数的函数参数名称?

假设我的function如下所示:

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的发明,该function可以通过默认参数跳闸。 这是一个快速的黑客应该在大多数情况下工作:

 var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg; 

我说大多数情况是因为有些东西会把它绊倒

 function (a=4*(5/3), b) {} // returns ['a'] 

编辑 :我也注意到vikasde也希望数组中的参数值。 这已经在一个名为arguments的局部variables中提供了。

摘自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments

参数对象不是一个数组。 它类似于一个数组,但没有任何数组属性,除了长度。 例如,它没有pop方法。 但是它可以转换成一个真正的数组:

 var args = Array.prototype.slice.call(arguments); 

如果Arraygenerics可用,则可以使用以下代码:

 var args = Array.slice(arguments); 

下面是从AngularJS取得的代码,它使用了dependency injection机制的技术。

这里是从http://docs.angularjs.org/tutorial/step_05取得的解释;

当控制器正在构build时,Angular的dependency injection器为您的控制器提供服务。 dependency injection器还负责创build服务可能具有的任何传递依赖(服务通常取决于其他服务)。

请注意,参数的名称是重要的,因为注入器使用这些来查找依赖关系。

 /** * @ngdoc overview * @name AUTO * @description * * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}. */ var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(.+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\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); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); fn.$inject = $inject; } } else if (isArray(fn)) { last = fn.length - 1; assertArgFn(fn[last], 'fn') $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); } return $inject; } 

这是一个更新的解决scheme,试图以紧凑的方式解决上述所有边缘案例:

 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 [""] } 

缩写testing输出(完整的testing用例附在下面):

 '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> 

解决方法是不容易出现空格和注释的错误是:

 var fn = function(/* whoa) */ hi, you){}; fn.toString() .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg,'') .match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1] .split(/,/) ["hi", "you"] 

很多这里的答案使用正则expression式,这是好的,但它不能处理语言的新增加(如箭头函数和类)。 另外值得注意的是,如果你在缩小的代码中使用了这些函数中的任何一个,它将会变成🔥。 它会使用任何缩小的名字。 Angular通过允许你传入一个有序的string数组来匹配这个参数的顺序。 那么解决scheme如下:

 var esprima = require('esprima'); var _ = require('lodash'); const parseFunctionArguments = (func) => { // allows us to access properties that may or may not exist without throwing // TypeError: Cannot set property 'x' of undefined const maybe = (x) => (x || {}); // handle conversion to string and then to JSON AST const functionAsString = func.toString(); const tree = esprima.parse(functionAsString); console.log(JSON.stringify(tree, null, 4)) // We need to figure out where the main params are. Stupid arrow functions 👊 const isArrowExpression = (maybe(_.first(tree.body)).type == 'ExpressionStatement'); const params = isArrowExpression ? maybe(maybe(_.first(tree.body)).expression).params : maybe(_.first(tree.body)).params; // extract out the param names from the JSON AST return _.map(params, 'name'); }; 

这处理原始分析问题和一些更多的函数types(例如箭头函数)。 下面是它能够处理和不能处理的一个想法:

 // I usually use mocha as the test runner and chai as the assertion library describe('Extracts argument names from function signature. 💪', () => { const test = (func) => { const expectation = ['it', 'parses', 'me']; const result = parseFunctionArguments(toBeParsed); result.should.equal(expectation); } it('Parses a function declaration.', () => { function toBeParsed(it, parses, me){}; test(toBeParsed); }); it('Parses a functional expression.', () => { const toBeParsed = function(it, parses, me){}; test(toBeParsed); }); it('Parses an arrow function', () => { const toBeParsed = (it, parses, me) => {}; test(toBeParsed); }); // ================= cases not currently handled ======================== // It blows up on this type of messing. TBH if you do this it deserves to // fail 😋 On a tech note the params are pulled down in the function similar // to how destructuring is handled by the ast. it('Parses complex default params', () => { function toBeParsed(it=4*(5/3), parses, me) {} test(toBeParsed); }); // This passes back ['_ref'] as the params of the function. The _ref is a // pointer to an VariableDeclarator where the ✨🦄 happens. it('Parses object destructuring param definitions.' () => { function toBeParsed ({it, parses, me}){} test(toBeParsed); }); it('Parses object destructuring param definitions.' () => { function toBeParsed ([it, parses, me]){} test(toBeParsed); }); // Classes while similar from an end result point of view to function // declarations are handled completely differently in the JS AST. it('Parses a class constructor when passed through', () => { class ToBeParsed { constructor(it, parses, me) {} } test(ToBeParsed); }); }); 

取决于你想使用它的ES6代理和解构可能是你最好的select。 例如,如果你想用它来进行dependency injection(使用参数的名字),那么你可以这样做:

 class GuiceJs { constructor() { this.modules = {} } resolve(name) { return this.getInjector()(this.modules[name]); } addModule(name, module) { this.modules[name] = module; } getInjector() { var container = this; return (klass) => { console.log(klass); var paramParser = new Proxy({}, { // The `get` handler is invoked whenever a get-call for // `injector.*` is made. We make a call to an external service // to actually hand back in the configured service. The proxy // allows us to bypass parsing the function params using // taditional regex or even the newer parser. get: (target, name) => container.resolve(name), // You shouldn't be able to set values on the injector. set: (target, name, value) => { throw new Error(`Don't try to set ${name}! 😑`); } }) return new klass(paramParser); } } } 

它不是那里最先进的parsing器,但它提供了一个如何使用代理来处理它的想法,如果你想使用简单的DI的参数parsing器。 然而,这种方法有一个小小的警告。 我们需要使用解构分配而不是正常的参数。 当我们传入喷射器代理时,解构就像调用对象上的getter一样。

 class App { constructor({tweeter, timeline}) { this.tweeter = tweeter; this.timeline = timeline; } } class HttpClient {} class TwitterApi { constructor({client}) { this.client = client; } } class Timeline { constructor({api}) { this.api = api; } } class Tweeter { constructor({api}) { this.api = api; } } // Ok so now for the business end of the injector! const di = new GuiceJs(); di.addModule('client', HttpClient); di.addModule('api', TwitterApi); di.addModule('tweeter', Tweeter); di.addModule('timeline', Timeline); di.addModule('app', App); var app = di.resolve('app'); console.log(JSON.stringify(app, null, 4)); 

这输出以下内容:

 { "tweeter": { "api": { "client": {} } }, "timeline": { "api": { "client": {} } } } 

它连接了整个应用程序。 最好的一点是,应用程序很容易testing(你可以实例化每个类,并通过模拟/存根/等)。 另外如果你需要换出实现,你可以从一个地方做到这一点。 所有这一切都是可能的,因为JS代理对象。

注意:在准备好用于生产之前,需要做很多工作,但它确实给出了它的样子。

答案有点迟,但可能会帮助其他人想到同样的事情。 👍

我知道这是一个古老的问题,但初学者已经复制了这个,好像这是在任何代码中的好习惯。 大多数情况下,不得不parsing一个函数的string表示来使用它的参数名称,这就隐藏了代码逻辑中的缺陷。

函数的参数实际上被存储在一个名为arguments的类似数组的对象中,其中第一个参数是arguments[0] ,第二个arguments[1]arguments[1]等等。 在圆括号中写参数名称可以被看作简写语法。 这个:

 function doSomething(foo, bar) { console.log("does something"); } 

…是相同的:

 function doSomething() { var foo = arguments[0]; var bar = arguments[1]; console.log("does something"); } 

variables本身存储在函数的作用域中,而不是作为对象的属性。 没有办法通过代码检索参数名称,因为它仅仅是代表人类语言variables的符号。

我总是把函数的string表示看作是一个debugging工具,特别是因为这个arguments是类似于数组的对象。 首先你不需要给参数名字。 如果尝试parsing一个string化的函数,它实际上并没有告诉你可能需要额外的未命名参数。

这是一个更糟和更常见的情况。 如果一个函数的参数多于3或4,那么传递一个对象可能是合乎逻辑的,这样更容易处理。

 function saySomething(obj) { if(obj.message) console.log((obj.sender || "Anon") + ": " + obj.message); } saySomething({sender: "user123", message: "Hello world"}); 

在这种情况下,函数本身将能够读取它接收到的对象并查找它的属性并获取它们的名字和值,但试图parsing函数的string表示只会给你参数的“obj”这根本没用。

 (function(a,b,c){}).toString().replace(/.*\(|\).*/ig,"").split(',') 

=> [“a”,“b”,“c”]

我已经尝试过这样做,但从来没有find一个实用的方法来完成它。 我结束了传递一个对象,然后循环。

 //define like function test(args) { for(var item in args) { alert(item); alert(args[item]); } } //then used like test({ name:"Joe", age:40, admin:bool }); 

我不知道这个解决scheme是否适合您的问题,但它可以让您重新定义您想要的任何function,而无需更改使用它的代码。 现有的调用将使用定位参数,而函数实现可能使用“命名参数”(一个单一的散列参数)。

我以为你会修改现有的函数定义,为什么没有一个工厂的function,只是你想要的:

 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> var withNamedParams = function(params, lambda) { return function() { var named = {}; var max = arguments.length; for (var i=0; i<max; i++) { named[params[i]] = arguments[i]; } return lambda(named); }; }; var foo = withNamedParams(["a", "b", "c"], function(params) { for (var param in params) { alert(param + ": " + params[param]); } }); foo(1, 2, 3); </script> </head> <body> </body> </html> 

希望它有帮助。

您也可以使用“esprima”parsing器来避免参数列表中的注释,空白和其他内容的许多问题。

 function getParameters(yourFunction) { var i, // safetyValve is necessary, because sole "function () {...}" // is not a valid syntax parsed = esprima.parse("safetyValve = " + yourFunction.toString()), params = parsed.body[0].expression.right.params, ret = []; for (i = 0; i < params.length; i += 1) { ret.push(params[i].name); } return ret; } 

它甚至适用于这样的代码:

 getParameters(function (hello /*, foo ),* /bar* { */,world) {}); // ["hello", "world"] 

我想宣布我的lib下Node.js也这样做: https : //github.com/cruks/cruks-lib-function

我不知道如何得到参数列表,但是你可以这样做来得到它所期望的数量。

 alert(doSomething.length); 

我通常如何做到这一点:

 function name(arg1, arg2){ var args = arguments; // array: [arg1, arg2] var objecArgOne = args[0].one; } name({one: "1", two: "2"}, "string"); 

你甚至可以通过函数名称来引用参数,如:

 name.arguments; 

希望这可以帮助!

 //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 

从@ jack-allan得到答案我稍微修改了这个函数,以允许ES6的默认属性,如:

 function( a, b = 1, c ){}; 

仍然返回[ 'a', 'b' ]

 /** * Get the keys of the paramaters of a function. * * @param {function} method Function to get parameter keys for * @return {array} */ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var ARGUMENT_NAMES = /(?:^|,)\s*([^\s,=]+)/g; function getFunctionParameters ( func ) { var fnStr = func.toString().replace(STRIP_COMMENTS, ''); var argsList = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')); var result = argsList.match( ARGUMENT_NAMES ); if(result === null) { return []; } else { var stripped = []; for ( var i = 0; i < result.length; i++ ) { stripped.push( result[i].replace(/[\s,]/g, '') ); } return stripped; } } 

这个答案需要3个步骤:

  1. 获取传递给函数的实际参数的值(我们称之为argValues )。 这是直接的,因为它将在函数内部作为arguments
  2. 从函数签名中获取参数名称(我们称之为argNames )。 这并不容易,需要parsing的function。 你不必自己做复杂的正则expression式,也不必担心边缘情况(默认参数,注释,…),你可以使用像babylon这样的库,将函数parsing成抽象语法树,从中获取参数的名称。
  3. 最后一步是将2个数组连接成1个具有所有参数的名称和值的数组。

代码将是这样的

 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) 

并logging的对象将是

 [ { "name": "a", "value": 1 }, { "name": "c", "value": 3 }, { "value": 4 } ] 

这里有一个工作示例https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a

我已经阅读了大部分的答案,我想补充一下。

 new RegExp(Function.name+'\\s*\\((.*?)\\)').exec(Function.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '') 

要么

 function getParameters(function) { return new RegExp(function.name+'\\s*\\((.*?)\\)').exec(function.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, ''); } 

假设你有一个function

 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){} 

__

说明

new RegExp(Function.name+'\\s*\\((.*?)\\)')

这将使用new RegExp(Function.name+'\\s*\\((.*?)\\)')创build一个正则指数 。 我必须使用new RegExp因为我正在向new RegExp注入一个variables( Function.name ,作为目标Function.name的名称)。

示例如果函数名称为“foo”( function foo() ),则RegExp将为/foo\s*\((.*?)\)/

Function.toString().replace(/\n/g, '')

然后它将整个函数转换成一个string,并删除所有换行符。 删除换行符有助于Camilo Martin提供的function设置。

.exec(...)[1]

这是RegExp.prototype.exec函数。 它基本上匹配正则指数( new RegExp() )到string( Function.toString() )。 然后[1]将返回在正则指数( (.*?) )中find的第一个捕获组 。

.replace(/\/\*.*?\*\//g, '').replace(/ /g, '')

这将删除/**/中的每个注释,并删除所有空格。


如果你想把所有的参数变成一个数组而不是一个用逗号分开的string,最后只需要添加.split(',')

 function getArgs(args) { var argsObj = {}; var argList = /\(([^)]*)/.exec(args.callee)[1]; var argCnt = 0; var tokens; while (tokens = /\s*([^,]+)/g.exec(argList)) { argsObj[tokens[1]] = args[argCnt++]; } return argsObj; } 

哇,这么多的答案已经..我很确定这被埋葬。 即使如此,我认为这可能是有用的一些。

我对ES6中所select的答案并不完全满意,它在默认值下不能很好地工作。 而且它也不提供默认值信息。 我也想要一个不依赖于外部库的轻量级函数。

此函数对于debugging目的非常有用,例如:使用其params,默认参数值和参数logging调用的函数。

我昨天花了一些时间,破解正确的RegExp来解决这个问题,这就是我想出的。 它工作得很好,我对结果非常满意:

 const REGEX_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; const REGEX_FUNCTION_PARAMS = /(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m const REGEX_PARAMETERS_VALUES = /\s*(\w+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm /** * Retrieve a function's parameter names and default values * Notes: * - parameters with default values will not show up in transpiler code (Babel) because the parameter is removed from the function. * - does NOT support inline arrow functions as default values * to clarify: ( name = "string", add = defaultAddFunction ) - is ok * ( name = "string", add = ( a )=> a + 1 ) - is NOT ok * - does NOT support default string value that are appended with a non-standard ( word characters or $ ) variable name * to clarify: ( name = "string" + b ) - is ok * ( name = "string" + $b ) - is ok * ( name = "string" + b + "!" ) - is ok * ( name = "string" + λ ) - is NOT ok * @param {function} func * @returns {Array} - An array of the given function's parameter [key, default value] pairs. */ function getParams(func) { let functionAsString = func.toString() let params = [] let match functionAsString = functionAsString.replace(REGEX_COMMENTS, '') functionAsString = functionAsString.match(REGEX_FUNCTION_PARAMS)[1] if (functionAsString.charAt(0) === '(') functionAsString = functionAsString.slice(1, -1) while (match = REGEX_PARAMETERS_VALUES.exec(functionAsString)) params.push([match[1], match[2]]) return params } // Lets run some tests! var defaultName = 'some name' function test1(param1, param2, param3) { return (param1) => param1 + param2 + param3 } function test2(param1, param2 = 4 * (5 / 3), param3) {} function test3(param1, param2 = "/root/" + defaultName + ".jpeg", param3) {} function test4(param1, param2 = (a) => a + 1) {} console.log(getParams(test1)) console.log(getParams(test2)) console.log(getParams(test3)) console.log(getParams(test4)) // [ [ 'param1', undefined ], [ 'param2', undefined ], [ 'param3', undefined ] ] // [ [ 'param1', undefined ], [ 'param2', '4 * (5 / 3)' ], [ 'param3', undefined ] ] // [ [ 'param1', undefined ], [ 'param2', '"/root/" + defaultName + ".jpeg"' ], [ 'param3', undefined ] ] // [ [ 'param1', undefined ], [ 'param2', '( a' ] ] // --> This last one fails because of the inlined arrow function! var arrowTest1 = (a = 1) => a + 4 var arrowTest2 = a => b => a + b var arrowTest3 = (param1 = "/" + defaultName) => { return param1 + '...' } var arrowTest4 = (param1 = "/" + defaultName, param2 = 4, param3 = null) => { () => param3 ? param3 : param2 } console.log(getParams(arrowTest1)) console.log(getParams(arrowTest2)) console.log(getParams(arrowTest3)) console.log(getParams(arrowTest4)) // [ [ 'a', '1' ] ] // [ [ 'a', undefined ] ] // [ [ 'param1', '"/" + defaultName' ] ] // [ [ 'param1', '"/" + defaultName' ], [ 'param2', '4' ], [ 'param3', 'null' ] ] console.log(getParams((param1) => param1 + 1)) console.log(getParams((param1 = 'default') => { return param1 + '.jpeg' })) // [ [ 'param1', undefined ] ] // [ [ 'param1', '\'default\'' ] ] 

You can access the argument values passed to a function using the "arguments" property.

  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]); 

Here's one way:

 // Utility function to extract arg name-value pairs function getArgs(args) { var argsObj = {}; var argList = /\(([^)]*)/.exec(args.callee)[1]; var argCnt = 0; var tokens; while (tokens = /\s*([^,]+)/g.exec(argList)) { argsObj[tokens[1]] = args[argCnt++]; } return argsObj; } // Test subject function add(number1, number2) { var args = getArgs(arguments); alert(args.toSource()); // ({number1:3,number2:4}) } // Invoke test subject add(3, 4); 

Note: This only works on browsers that support arguments.callee .

It's pretty easy.

At the first there is a deprecated arguments.callee — a reference to called function. At the second if you have a reference to your function you can easily get their textual representation. At the third if you calling your function as constructor you can also have a link via yourObject.constructor. NB: The first solution deprecated so if you can't to not use it you must also think about your app architecture. If you don't need exact variable names just use inside a function internal variable arguments without any magic.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee

All of them going to call toString and replace with re so we can create a helper:

 // getting names of declared parameters var getFunctionParams = function (func) { return String(func).replace(/[^\(]+\(([^\)]*)\).*/m, '$1'); } 

一些例子:

 // Solution 1. deprecated! don't use it! var myPrivateFunction = function SomeFuncName (foo, bar, buz) { console.log(getFunctionParams(arguments.callee)); }; myPrivateFunction (1, 2); // Solution 2. var myFunction = function someFunc (foo, bar, buz) { // some code }; var params = getFunctionParams(myFunction); console.log(params); // Solution 3. var cls = function SuperKewlClass (foo, bar, buz) { // some code }; var inst = new cls(); var params = getFunctionParams(inst.constructor); console.log(params); 

Enjoy with JS!

UPD: Jack Allan was provided a little bit better solution actually. GJ Jack!

Whatever the solution, it must not break on wierd functions, whose toString() looks just as wierd:

 function ( A, b ,c ,d ){} 

screenshot from console

Also, why use complex regular expressions? 这可以像这样完成:

 function getArguments(f) { return f.toString().split(')',1)[0].replace(/\s/g,'').substr(9).split(','); } 

This works everywhere with every function, and the only regex is whitespace removal that doesn't even process the whole string due to the .split trick.

Ok so an old question with plenty of adequate answers. here is my offering that does not use regex, except for the menial task of stripping whitespace . (I should note that the "strips_comments" function actually spaces them out, rather than physically remove them. that's because i use it elsewhere and for various reasons need the locations of the original non comment tokens to stay intact)

It's a fairly lengthy block of code as this pasting includes a mini test framework.

  function do_tests(func) { if (typeof func !== 'function') return true; switch (typeof func.tests) { case 'undefined' : return true; case 'object' : for (var k in func.tests) { var test = func.tests[k]; if (typeof test==='function') { var result = test(func); if (result===false) { console.log(test.name,'for',func.name,'failed'); return false; } } } return true; case 'function' : return func.tests(func); } return true; } function strip_comments(src) { var spaces=(s)=>{ switch (s) { case 0 : return ''; case 1 : return ' '; case 2 : return ' '; default : return Array(s+1).join(' '); } }; var c1 = src.indexOf ('/*'), c2 = src.indexOf ('//'), eol; var out = ""; var killc2 = () => { out += src.substr(0,c2); eol = src.indexOf('\n',c2); if (eol>=0) { src = spaces(eol-c2)+'\n'+src.substr(eol+1); } else { src = spaces(src.length-c2); return true; } return false; }; while ((c1>=0) || (c2>=0)) { if (c1>=0) { // c1 is a hit if ( (c1<c2) || (c2<0) ) { // and it beats c2 out += src.substr(0,c1); eol = src.indexOf('*/',c1+2); if (eol>=0) { src = spaces((eol-c1)+2)+src.substr(eol+2); } else { src = spaces(src.length-c1); break; } } else { if (c2 >=0) { // c2 is a hit and it beats c1 if (killc2()) break; } } } else { if (c2>=0) { // c2 is a hit, c1 is a miss. if (killc2()) break; } else { // both c1 & c2 are a miss break; } } c1 = src.indexOf ('/*'); c2 = src.indexOf ('//'); } return out + src; } function function_args(fn) { var src = strip_comments(fn.toString()); var names=src.split(')')[0].replace(/\s/g,'').split('(')[1].split(','); return names; } function_args.tests = [ function test1 () { function/*al programmers will sometimes*/strip_comments_tester/* because some comments are annoying*/( /*see this---(((*/ src//)) it's an annoying comment does not help anyone understand if the ,code,//really does /**/sucks ,much /*?*/)/*who would put "comment\" about a function like (this) { comment } here?*/{ } var data = function_args(strip_comments_tester); return ( (data.length==4) && (data[0]=='src') && (data[1]=='code') && (data[2]=='sucks') && (data[3]=='much') ); } ]; do_tests(function_args); 

I'll give you a short example below:

 function test(arg1,arg2){ var funcStr = test.toString() var leftIndex = funcStr.indexOf('('); var rightIndex = funcStr.indexOf(')'); var paramStr = funcStr.substr(leftIndex+1,rightIndex-leftIndex-1); var params = paramStr.split(','); for(param of params){ console.log(param); // arg1,arg2 } } test(); 

This package uses recast in order to create an AST and then the parameter names are gathered from their, this allows it to support pattern matching, default arguments, arrow functions and other ES6 features.

https://www.npmjs.com/package/es-arguments

By using the arguments array in JS:

 function doSomething(){ for (var i = 0, j = arguments.length; i < j; i++){ alert(arguments[i]); } } doSomething('a','b','c') 

function parameter string value image dynamically from JSON . Since item.product_image2 is a URL string, you need to put it in quotes when you call changeImage inside parameter.

My Function Onclick

 items+='<img src='+item.product_image1+' id="saleDetailDivGetImg">'; items+="<img src="+item.product_image2+" onclick='changeImage(\""+item.product_image2+"\");'>"; 

My Function

 <script type="text/javascript"> function changeImage(img) { document.getElementById("saleDetailDivGetImg").src=img; alert(img); } </script>