简体   繁体   中英

Writing a function with variable number of input arguments

I have a javascript function whose number of input arguments is not known ( has variable number of arguments) and it has also an input dictionary argument called "kwargs" argument which can have some other arguments as (key,value), like this:

function plot( data, kwargs={}){
}

I want to get both the "name" and "value" of the arguments in the body of the function when I call the function with a number of arguments. Suppose that I want to have a function call like this:

plot(lines, xlabel="Project", 
        ylabel="Investor", 
        xfmt="%", xscale=100, yfmt="%.", yscale=100)

I want to gain "xlable", "Project", "ylabel", "Investor", "xfmt","%" and so on(maybe more arguments) in the function definition.

How can I write 'plot' function def?

function plot( data, kwargs={},...restArguments){
                                                }

Then you can get the values by restArguments array but you cant get the name of the arguments.

Since JavaScript doesn't support named arguments, your best bet would be to use the dictionary-approach described below for the variable parameters.

You can:

  1. Use a dictionary as an argument. That would allow you to access the "arguments" by their property-name.
    However, that would require the caller to pass an object, which is potentially created every time the function is called, giving your program some addititonal overhead.
  2. Use the arguments object . This works for every version of ECMAScript.
    However, you would have to access it with an offset equal to the amount of named parameters.
  3. Use the Rest Parameter-syntax . This works since ES6 and is recommended over the arguments -approach.

Note that without some refactoring, you will not be able to use approach 2 and 3.

Using a dicionary

Take an object as a parameter and take use properties as the actual parameters. That way, you can (kind of) refer to them by their identifier.

This would make this:

function aFunc(aVar, anotherVar, aThirdVar) {
  console.log(aVar, anotherVar, aThirdVar);
}

To this:

function aFunc(data) {
  console.log(data.aVar, data.anotherVar, data.aThirdVar);
}

And the new function could be called like this:

aFunc({aVar: 5, anotherVar: 10, aThirdVar: 20}); // Works
// -- or --
// Note the un-ordered properties
aFunc({aThirdVar: 20, aVar: 5, anotherVar: 10}); // Also works

However, this comes with the following problems:

  • It isn't intuitive to how functions are called
  • Defining fallback-values for properties has to be implemented in a non-native way.
    One could achieve this by short-circuiting like this: data.var ||= 'fallback-value'; .
  • IDEs cannot statically check your code for errors before execution
  • The parameter-list isn't helpful for the developer
  • Most significant: An actual object would have to be passed. This is most likely created just for one call, which would give the programm unnecessary overhead when the function is called multiple times.

The advantages of using this approach are:

  • "Parameters" are defined as properties of an object. This keeps the lexical scope clean(-er).
    However, this should not be a factor for deciding what approach to choose.
  • Since properties of an object are (by default) enumerable, you can both get the name of the property as well as the value of it (this might be what you are aiming for).

Using the arguments object

Since arguments is present in all versions of ECMAScript, I would recommend this approach when aiming for (quite a bit of) backwards-compatibility.

arguments is present in any function execution context, meaning in both function declarations as well as function expressions , however not in arrow-function (lambda) expressions (added in ES6; for ES6 usage, using the Rest Parameter-syntax is recommended anyway).

Using this, you can use the parameters of a function as well as access any further parameter not listed in the parameter-list of a function.

Quoting from Google's JavaScript Style Guide :

Functions that take a variable number of arguments should have the last argument named var_args. You may not refer to var_args in the code; use the arguments array.

Note that just because Google does it this way doesn't mean that this is the way one should code. It is just a guide(.) for how to code when working on code from Google.

Here is an example following Google's Style Guide:

function aFunc(first, second, var_args) {
  console.log(first, second, arguments[2], arguments[3]);
}

aFunc(5, 10, 20); // => '5 10 20 undefined'

Using the Rest Parameter-syntax

Both the Rest Parameter-syntax as well as the arrow-function (lambda) expression were introduced in ES6.

Since this is recommended over using the arguments object, one should try to implement this approach when deciding which one of the two to use, because accessing the remaining parameters is more intuitive, it also works with arrow-function expressions, and the Rest Parameter is an actual array.

Because the Rest Parameter is an actual array, one can use the Spread Syntax as well as any functionality inherited by Array , unlike the arguments object.

Here is an example similar to the arguments object-approach, now using the Rest Parameter-syntax instead:

function aFunc(first, second, ...rest) {
  console.log(first, second, rest[0], rest[1]);
}

aFunc(5, 10, 20);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM