How to get function parameter names/values dynamically? How to get function parameter names/values dynamically? javascript javascript

How to get function parameter names/values dynamically?


The following function will return an array of the parameter names of any function passed in.

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;}

Example usage:

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

Edit:

With the invent of ES6 this function can be tripped up by default parameters. Here is a quick hack which should work in most cases:

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

I say most cases because there are some things that will trip it up

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

Edit:I also note vikasde wants the parameter values in an array also. This is already provided in a local variable named arguments.

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

The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length. For example, it does not have the pop method. However it can be converted to a real Array:

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

If Array generics are available, one can use the following instead:

var args = Array.slice(arguments);


Below is the code taken from AngularJS which uses the technique for its dependency injection mechanism.

And here is an explanation of it taken from http://docs.angularjs.org/tutorial/step_05

Angular's dependency injector provides services to your controller when the controller is being constructed. The dependency injector also takes care of creating any transitive dependencies the service may have (services often depend upon other services).

Note that the names of arguments are significant, because the injector uses these to look up the dependencies.

/** * @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;}


Here is an updated solution that attempts to address all the edge cases mentioned above in a compact way:

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

Abbreviated test output (full test cases are attached below):

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