How to get function parameter names/values dynamically?

前端 未结 30 2585
说谎
说谎 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:35

    Note: if you want to use ES6 parameter destructuring with the top solution add the following line.

    if (result[0] === '{' && result[result.length - 1 === '}']) result = result.slice(1, -1)
    
    0 讨论(0)
  • 2020-11-22 00:36

    How I typically do it:

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

    You can even ref the args by the functions name like:

    name.arguments;
    

    Hope this helps!

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

    The answer to this requires 3 steps:

    1. To get the values of the actual parameters passed to the function (let's call it argValues). This is straight forward as it will be available as arguments inside the function.
    2. To get the parameter names from the function signature (let's call it argNames). This not as easy and requires parsing the function. Instead of doing the complex regex yourself and worrying about edge cases (default parameters, comments, ...), you can use a library like babylon that will parse the function into an abstract syntax tree from which you can obtain the names of parameters.
    3. The last step is to join the 2 arrays together into 1 array that has the name and value of all the parameters.

    The code will be like this

    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)
    

    and the logged object will be

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

    And here's a working example https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a

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

    I have read most of the answers here, and I would like to add my one-liner.

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

    or for a one-liner function in ECMA6

    var getParameters = func => new RegExp('(?:'+func.name+'\\s*|^)\\s*\\((.*?)\\)').exec(func.toString().replace(/\n/g, ''))[1].replace(/\/\*.*?\*\//g, '').replace(/ /g, '');
    

    __

    Let's say you have a function

    function foo(abc, def, ghi, jkl) {
      //code
    }
    

    The below code will return "abc,def,ghi,jkl"

    That code will also work with the setup of a function that Camilo Martin gave:

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

    Also with Bubersson's comment on Jack Allan's answer:

    function(a /* fooled you)*/,b){}
    

    __

    Explanation

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

    This creates a Regular Expression with the new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)'). I have to use new RegExp because I am injecting a variable (Function.name, the name of the function being targeted) into the RegExp.

    Example If the function name is "foo" (function foo()), the RegExp will be /foo\s*\((.*?)\)/.

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

    Then it converts the entire function into a string, and removes all newlines. Removing newlines helps with the function setup Camilo Martin gave.

    .exec(...)[1]

    This is the RegExp.prototype.exec function. It basically matches the Regular Exponent (new RegExp()) into the String (Function.toString()). Then the [1] will return the first Capture Group found in the Regular Exponent ((.*?)).

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

    This will remove every comment inside /* and */, and remove all spaces.


    This also now supports reading and understanding arrow (=>) functions, such as f = (a, b) => void 0;, in which Function.toString() would return (a, b) => void 0 instead of the normal function's function f(a, b) { return void 0; }. The original regular expression would have thrown an error in its confusion, but is now accounted for.

    The change was from new RegExp(Function.name+'\\s*\\((.*?)\\)') (/Function\s*\((.*?)\)/) to new RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)') (/(?:Function\s*|^)\((.*?)\)/)


    If you want to make all the parameters into an Array instead of a String separated by commas, at the end just add .split(',').

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

    The proper way to do this is to use a JS parser. Here is an example using acorn.

    const acorn = require('acorn');    
    
    function f(a, b, c) {
       // ...
    }
    
    const argNames = acorn.parse(f).body[0].params.map(x => x.name);
    console.log(argNames);  // Output: [ 'a', 'b', 'c' ]
    

    The code here finds the names of the three (formal) parameters of the function f. It does so by feeding f into acorn.parse().

    0 讨论(0)
提交回复
热议问题