How to get function parameter names/values dynamically?

前端 未结 30 2442
说谎
说谎 2020-11-22 00:13

Is there a way to get the function parameter names of a function dynamically?

Let’s say my function looks like this:

function doSomething(param1, par         


        
相关标签:
30条回答
  • 2020-11-22 00:29

    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]);    
    
    0 讨论(0)
  • 2020-11-22 00:30

    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);
    
    0 讨论(0)
  • 2020-11-22 00:30

    Solution that is less error prone to spaces and comments would be:

    var fn = function(/* whoa) */ hi, you){};
    
    fn.toString()
      .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg,'')
      .match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1]
      .split(/,/)
    
    ["hi", "you"]
    
    0 讨论(0)
  • 2020-11-22 00:30

    As this has not yet been mentioned, if you are using Typescript you can emit meta-data when using Decorators which will allow you to get the parameter names and types.

    Metadata will only be emitted if the class/function/prop has a decorator on it.
    It doesn't matter which decorator.

    This feature can be enabled by setting emitDecoratorMetadata to true inside tsconfig.json

    {
      "compilerOptions": {
        "emitDecoratorMetadata": true
      }
    }
    

    As the metadata is still an early proposal the reflect-metadata package must be installed or Reflect.getMetadata will not be defined.

    npm install reflect-metadata
    

    You can use it as follows:

    const AnyDecorator = () : MethodDecorator => {
        return target => { }
    }
    
    class Person{
        @AnyDecorator()
        sayHello(other: Person){}
    }
    const instance = new Person();
    const funcType = Reflect.getMetadata('design:type', instance.sayHello);
    const funcParams = Reflect.getMetadata('design:paramtypes', instance.sayHello);
    

    In newer versions of Angular for instance this is used to determine what to inject -> https://stackoverflow.com/a/53041387/1087372

    0 讨论(0)
  • 2020-11-22 00:30

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

    Some examples:

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

    0 讨论(0)
  • 2020-11-22 00:31

    Taking the answer from @jack-allan I modified the function slightly to allow ES6 default properties such as:

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

    to still return [ '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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题