Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow either named arguments or positional arguments in Javascript

How can I have a function accept either named arguments (foo({a: 'hello', b: 'it is me'})) or positional arguments (foo('hello', 'it is me'))?

I understand that named arguments can be simulated by passing an object to the function:

function foo(options) {
    options = options || {};
    var a = options.a || 'peanut'; // whatever default value
    var b = options.b || 'butter'; // whatever default value
    console.log(a, b);
}

// ES6 allows automatic destructuring
function foo({a = 'peanut', b = 'butter'} = {}) {
    console.log(a, b);
}

But that does not allow me to accept positional arguments to be passed.

I would like to use ES6 but anything from ES5 would be ok too.

like image 908
AKG Avatar asked Dec 17 '15 06:12

AKG


People also ask

What is a positional argument JavaScript?

The important takeaway here is that the name of the argument doesn't have any significance. The only thing that matters is the order in which the arguments are passed. This familiar approach is called positional arguments.

What are named arguments in JavaScript?

As we can see what we call named arguments is nothing more than a destructuring of the keys of an object that in this case will act as "arguments" of the function.

Which function accepts two arguments in JavaScript?

Let's start by creating a function called add that can accept 2 arguments and that returns their sum. We can use Node. js to run the code node add_2_numbers.

Can you use a mix of positional and keyword argument passing?

Functions with a mix of positional arguments and keyword arguments. It is common to have functions with both positional arguments (with and without default value )and key word arguments (with and without default value) with the help of / and * symbols (from Python 3.8 ).


2 Answers

First of all, I really would recommend to stick with one approach. As you said, use either "named"

function foo({a = 'peanut', b = 'butter'} = {}) {
    console.log(a, b);
}

or positional arguments:

function foo(a = 'peanut', b = 'butter') {
    console.log(a, b);
}

Choose the one that fits your function better, do not mix both.


If you really need both for some reason, standard overloading techniques are available to you. It'll only work properly if your first positional argument is not an object. I would propose one of the following idioms:

function foo(a, b) { // positional is normal case
    if (arguments.length == 1 && typeof arguments[0] == "object")
        {a, b} = arguments[0];

    console.log(a, b);
}
function foo({a, b}) { // named is normal case
    if (arguments.length > 1 || typeof arguments[0] != "object")
        [a, b] = arguments;

    console.log(a, b);
}

and if you need default values, it gets ugly either way:

function foo(a, b) {
    var opts = (arguments.length == 1 && typeof arguments[0] == "object")
      ? arguments[0]
      : {a, b};
    ({a = 'peanut', b = 'butter'} = opts);

    console.log(a, b);
}
like image 128
Bergi Avatar answered Sep 27 '22 17:09

Bergi


I suppose something like this would work:

function foo(...options){
   if (typeof options[0] === 'object'){
    console.log('expect object', options[0]);
  }else{
    console.log('expect array', options);  
  }
}

foo('peanut', 'butter');
foo({a:'peanut', b:'butter'});
like image 21
glued Avatar answered Sep 27 '22 16:09

glued