Skip arguments in a JavaScript function

Javascript

Javascript Problem Overview


I have a function like this:

function foo(a, b, c, d, e, f) {
}

In order to call this function only with an f argument, I know I should do:

foo(undefined, undefined, undefined, undefined, undefined, theFValue);

Is there a less verbose way to do this?

Solutions:
I selected some proposed solutions (without using helper third functions)

// zero - ideal one, actually not possible(?!)
foo(f: fValue);

// one - asks a "strange" declaration
var _ = undefined;
foo(_, _, _, _, _, fValue);

// two - asks the {} to be used instead of a 'natural' list of args
//     - users should be aware about the internal structure of args obj
//       so this option is not 'intellisense friendly'
function foo(args){
    // do stuff with `args.a`, `args.b`, etc.
}    
foo({f: fValue});

Javascript Solutions


Solution 1 - Javascript

Such:

foo(undefined, undefined, undefined, undefined, undefined, arg1, arg2);

.is equal to:

foo(...Array(5), arg1, arg2);

.or:

foo(...[,,,,,], arg1, arg2);

Such:

foo(undefined, arg1, arg2);

.is equal to:

foo(...Array(1), arg1, arg2);

.or:

foo(...[,], arg1, arg2);

Such:

foo(arg1, arg2);

.is equal to:

foo(...Array(0), arg1, arg2);

.or:

foo(...[], arg1, arg2);

Solution 2 - Javascript

You could use apply:

foo.apply(this, Array(5).concat([theFValue]));

In this case, 5 is the amount of parameters you want to skip.

Wrap that in a function:

function call(fn, skipParams, parameter) {
    fn.apply(this, Array(skipParams).concat([parameter]));
}

call(foo, 5, theFValue);

However, in that case the scope of this is different, so you may need to pass that, too:

function call(fn, skipParams, parameter, thisArg) {
    fn.apply(thisArg, Array(skipParams).concat([parameter]));
}

call(foo, 5, theFValue, this);

Then again, this implementation only allows 1 parameter to be passed. Let's improve that:

function call(fn, skipParams, parameters, thisArg) {
    fn.apply(thisArg, Array(skipParams).concat(parameters));
}

call(foo, 5, [theFValue, theGValue, theHValue], this);

That's starting to get a "little" verbose. It also doesn't handle missing parameters after the first parameter that well, unless you want to pass undefined:

call(foo, 5, [theFValue, theGValue, theHValue, undefined, theJValue], this);

Or, something completely different:

var _ = undefined;
foo(_,_,_,_,_, theFValue);

On a more serious note:

Your best option to deal with optional parameters, is to change the way you're handling parameters. Simply pass an object:

function foo(parameters){
    // do stuff with `parameters.a`, `parameters.b`, etc.
}

foo({c: 1, g: false});

This approach doesn't suffer from any of the drawbacks in the earlier examples.

Solution 3 - Javascript

A better way to deal with optional arguments is to pass an object whose attributes you look up:

function foo(options) {
    var a = options.a,
        b = options.b,
        c = options.c,
        d = options.d,
        e = options.e,
        f = options.f;
}

foo({ f: 15 });

Solution 4 - Javascript

Skip function:

const skip = (num) => new Array(num);

Skipping beginning params:

foo(...skip(4), f);

Skipping end params:

foo(f, ...skip(4));

Skipping middle params:

foo(f, ...skip(4), f2);

Solution 5 - Javascript

If you will pass an object with a property name f so you can use destructuring assignment with ES6 syntax like this:

function foo({ f }) {
  console.log(f);
}
    
foo({ g: 5, f: 10 });

Solution 6 - Javascript

If this is something you're going to want to do often, then consider a simple wrapper:

function bar(f) {
    foo(undefined, undefined, undefined, undefined, undefined, f);
}

If you're only doing this once, or you're wanting a random permutation of the parameters then this approach isn't the best.

Solution 7 - Javascript

Use bind for a partial application:

function foo(a, b, c, d, e, f) { document.write(f); }

function skip(f, n) {
    while (n--) {
        f = f.bind(null, undefined);
    }
    return f;
}

skip(foo, 5)('hallo');

Solution 8 - Javascript

I provide some methods that may help you achieve, as below,

  1. Destructuring assignment (recommend)
  2. Optional_chaining

Method1: Destructuring assignment

Example1

function Person(name, {id="007", age=-1, info={msg:null, mood:undefined}}) {
  return [name, id, age, info.msg, info.mood]
}

// šŸ‘‡ Test Only
for (const [result, expected] of [
  [Person("Carson", {}), // If you don't need any options then must set "" or {}
    ["Carson", "007", -1, null, undefined]
  ],
  [Person("Aoo", {
    age: 29,
    info: {
      msg: "hello world"
    }
  }),
    ["Aoo", "007", 29, "hello world", undefined]
  ],
  [Person("Boo", {
    id: "003",
    info: {
      mood: "Happy"
    }
  }),
    ["Boo", "003", -1, null, "Happy"]
  ]
]) {
  console.log(JSON.stringify(result))
  console.log(JSON.stringify(result) === JSON.stringify(expected))
}

Example 2

const user = {
  id: 42,
  displayName: 'jdoe',
  fullName: {
    firstName: 'John',
    lastName: 'Doe'
  }
};

function userId({id}) {
  return id;
}

function whois({displayName, fullName: {firstName: name}}) {
  return `${displayName} is ${name}`;
}

console.log(userId(user)); // 42
console.log(whois(user));  // "jdoe is John"

ļ‘† source code from object_destructuring search Unpacking fields from objects passed as a function parameter

Method2

Use Optional_chaining to set the default value

const val = obj ?? "default value" // if obj is undefined then val = default value
const val = obj?.msg // equal to obj.msg if {msg:...} exists in the obj. Otherwise, undefined

for example

/*
Assume your options is:
{
  id:"",
  info:{
    msg:"",
    mood: "",
  }
}
*/
function MyFunc(name, options = {}) {
  const id = options.id ?? "007"
  const msg = options.info?.msg ?? null
  const mood = options.info?.mood
  // ...
}
Example

function Person(name, options = {}) {
  const id = options.id ?? "007"
  const msg = options.info?.msg ?? null
  const mood = options.info?.mood
  return [name, id, msg, mood]
}


for (const [result, expected] of [
  [Person("Carson"),
    ["Carson", "007", null, undefined]
  ],
  [Person("Aoo", {
    info: {
      msg: "hello world"
    }
  }),
    ["Aoo", "007", "hello world", undefined]
  ],
  [Person("Boo", {
    id: "003",
    info: {
      mood: "Happy"
    }
  }),
    ["Boo", "003", null, "Happy"]
  ]
]) {
  console.log(JSON.stringify(result) === JSON.stringify(expected))
}

Method 2.extend

If you want the IDE to know what the options is, you may consider using the below method,

function PersonOptions(options={}) {
  this.id = options.id ?? "007"
  this.msg = options.info?.msg ?? null
  this.mood = options.info?.mood
}

function Person2(name, options = new PersonOptions()) {
  return [name, options.id, options.msg, options.mood]
}

for (const [result, expected] of [
  [Person2("Carson"),
    ["Carson", "007", null, undefined]
  ],
  [Person2("Aoo", new PersonOptions({
    info: {
      msg: "hello world"
    }
  })),
    ["Aoo", "007", "hello world", undefined]
  ],
  [Person2("Boo", new PersonOptions({
    id: "003",
    info: {
      mood: "Happy"
    }
  })),
    ["Boo", "003", null, "Happy"]
  ]
]) {
  console.log(JSON.stringify(result) === JSON.stringify(expected))
}

Solution 9 - Javascript

How about

function multiply(a = 2, b = 1) {
  return a * b;
}

console.log(multiply(undefined, 3));
// expected output: 6

If you pass a param undefined, it will use the default value from the definition.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsergeView Question on Stackoverflow
Solution 1 - JavascriptPacerierView Answer on Stackoverflow
Solution 2 - JavascriptCerbrusView Answer on Stackoverflow
Solution 3 - JavascriptMichael LaszloView Answer on Stackoverflow
Solution 4 - JavascriptsookieView Answer on Stackoverflow
Solution 5 - JavascriptIdan DaganView Answer on Stackoverflow
Solution 6 - JavascriptTroView Answer on Stackoverflow
Solution 7 - JavascriptNina ScholzView Answer on Stackoverflow
Solution 8 - JavascriptCarsonView Answer on Stackoverflow
Solution 9 - JavascriptTrigunaView Answer on Stackoverflow