0

say I have this

function isdef(x) { return typeof x !== 'undefined'; }

function banana(a, b, c) {
    if (!isdef(a)) a = 1;
    if (!isdef(b)) b = 2;
    if (!isdef(c)) c = 3;
    ...
}

So all of the arguments are optional. If I want to call it with just c argument I'd have to write

banana(undefined, undefined, 5);

which is kinda clunky.

Sure I could do something like

window.k = undefined;
...
banana(k, k, 5);

But I'd really rather not make short window scope variables.

In vb.net for example, I could write

banana(,,5)

but js doesn't like that.

Is there a convenient way to do skip an argument in a function call?

user81993
  • 6,167
  • 6
  • 32
  • 64
  • http://stackoverflow.com/questions/34388641/javascript-function-with-optional-parameters – Amr Magdy Sep 24 '16 at 03:54
  • Possible duplicate of [How to overload functions in javascript?](http://stackoverflow.com/questions/10855908/how-to-overload-functions-in-javascript) – Mark Schultheiss Sep 24 '16 at 04:11
  • `banana(undefined, undefined, 5)` would not set `c` to `3` as condition at `if` is `!isdef(c)` . What is expected result of `banana(undefined, undefined, 5);`? – guest271314 Sep 24 '16 at 04:12
  • @guest271314 its expected that the function runs with c = 5 :p – user81993 Sep 24 '16 at 14:27

5 Answers5

2

you can pass an object instead

function banana(options) {
     if (!isdef(options.a)) a = 1;
     if (!isdef(options.b)) b = 1;
}

banana({a:1});
monkeyinsight
  • 4,719
  • 1
  • 20
  • 28
1

I think there is no way in JavaScript you can only provide the later arguments without passing the first arguments. And I'm not sure about your requirements. But here is my approach. Please feel free to reply.

function banana(bananaObj){
  bananaObj = bananaObj || {};
  bananaObj.a = bananaObj.a || 1;
  bananaObj.b = bananaObj.b || 2;
  bananaObj.c = bananaObj.c || 3;
  document.write('bananaObj: ', JSON.stringify(bananaObj));
}
banana({c:10})
Mahavir
  • 322
  • 4
  • 8
1

Is there a convenient way to skip an argument in a function call?

Not directly.

This topic was discussed on the ES Discuss mailing group. The reception to that proposal was frosty, to say the least. It was also suggested to make parameters in function definitions optional:

function foo(a, , b) { }

Your options include:

  1. Using spread syntax as follows:

    banana(...[,,5])
    
  2. Re-order the parameters to put the optional ones at the end.

  3. Write a higher-level function which transforms functions to add additional leading arguments:

    function prefixArgs(fn, n) {
      return function(...args) { 
        return fn(...Array(n), ...args); 
      };
    }
    
    prefixArgs(banana, 2)(5)
    
  4. Use an object instead of a list of parameters, as suggested in other answers.

  5. "Curry" the function, as

    function banana(a = 1) {
      return function(b = 2) {
        return function(c = 3) {
          return SOMETHING-USING-A-B-AND-C;
        };
      };
    }
    
    banana()()(5)
    

Notice that in the above I've used parameter defaults. They're a good alternative to the checks you wrote for undefined:

function banana(a = 1, b = 2, c = 3) {
  ...
}

although this itself does not solve the problem of how to pass in leading optional parameters. You can use this implementation of banana in conjunction with some of the ideas above.

Support. Note that spread parameters and parameter defaults are ES6 features. If you're not familiar with them, you should start learning about them. If you need to target browsers such as IE which don't support them natively, then you'll need to transpile using well-known tools such as Babel.

  • note that spread syntax and parameter defaults are ES6-only and are not/may not be yet supported by all browsers – miraculixx Sep 24 '16 at 04:45
0

You can declare required arguments first, and followed by optional arguments in this way:

function banana(a, b, c) {
    b = b || 0;
    c = c || 0;
    // a is required, b and c is optional, either b or 0
}

Call the function banana(1) which omits b and c, or provide all the argument banana(1, 2, 3).

Another method is to declare arguments to a object so that you don't need to remember the order or the number of your arguments.

function banana(args) {
    // set defaults
    args.a = args.a || 0;    
    args.b = args.b || 0;
    args.c = args.c || 0;
}

Call the function banana({ a: 1, b: 2 }).

WangYudong
  • 4,335
  • 4
  • 32
  • 54
  • 1
    This doesn't solve the problem which was to omit arguments **earlier** in the parameter list. Anyway, why would I do this instead of using parameter defaults? –  Sep 24 '16 at 04:12
  • @torazaburo You are right that parameter can have no meaning at all rather than set to the default. But my first method does skip the arguments that not to be assigned. And at some situation, setting a number to 0 is an option for its default value. – WangYudong Sep 24 '16 at 04:21
0

You could use rest parameter, Array.prototype.map(), bracket notation. Pass index to select as first parameter to banana or null if all variables should be returned

function isdef(x) {
  return typeof x !== 'undefined';
}

function banana(i, ...args) {
  var res = i ? [!isdef(args[i])] : args.map(value => !isdef(value));
  return res.length === 1 ? res[0] : res;
}

console.log(banana(2, undefined, undefined, 5));
console.log(banana(null, undefined, undefined, 5));
guest271314
  • 1
  • 15
  • 104
  • 177