8

I'm trying to use named function arguments and default values using destructuring.

function doSomething({arg1 = "foo", arg2 = "bar"} = {}) {
  console.log(arg1, arg2);
}

but I would also like to have access to the entire object, in case the user adds some extra fields. This doesn't actually work, but I'm shooting for something like this:

function doSomething(parameters = {arg1 = "foo", arg2 = "bar"} = {}) {
  console.log(arg1, arg2, parameters);   
  // parameters should contain arg1 and arg2, plus any additional user supplied keys.
}

Is there an elegant way to do this using destructuring? (I tried using arguments[0] but this doesn't actually include my default values for arg1, and arg2.)

Thanks.

  • Possible duplicate of [arrow functions: destructuring arguments and grabbing them as a whole at the same time](https://stackoverflow.com/questions/47117312/arrow-functions-destructuring-arguments-and-grabbing-them-as-a-whole-at-the-sam) – Sebastian Simon Apr 04 '18 at 07:16

3 Answers3

3

You could do:

function doSomething({ arg1 = "foo", arg2 = "bar", ...otherParams } = {}) {
    console.log(arg1, arg2, otherParams);
}

...and then:

doSomething({ anotherParam: 'hello' });

...would log:

foo bar {anotherParam: "hello"}

This uses the spread operator, which you can play around with in the latest Chrome, and use in production apps that you are transpiling to ES5 with Babel. It's worth noting, however, that this adds more complex transpiled code while it is not supported in all browsers natively.

Also, from a code readability and architectural perspective, this function now has a lot of complexity with destructuring, default arguments, and the spread operator, so I would see if it is possible to simplify what you're doing to reduce the need to use all of these.

For example, if you were building a function to create a DOM element, you could write:

function createDOMElement(properties = {}) {
   // Could avoid `const` by doing destructuring in the function signature, but broke it onto another line for better readability.
   const {
    tagName = 'div',
    ...attributes
   } = properties;

   const anElement = document.createElement(tagName);
   Object.keys(attributes).forEach((key) => anElement.setAttribute(key, attributes[key]));
   return anElement;
}

...but you could just supply the tag name as a regular argument not a named argument and simplify it to:

function createDOMElement(tagName = 'div', attributes = {}) {
   const anElement = document.createElement(tagName);
   Object.keys(attributes).forEach((key) => anElement.setAttribute(key, attributes[key]));
   return anElement;
}
Steve Harrison
  • 121,227
  • 16
  • 87
  • 72
0

With the upcoming version of Javascript, you could use rest parameters for additional properties.

function doSomething({ arg1 = "foo", arg2 = "bar", ...rest } = {}) {
  console.log(arg1, arg2, rest);
}

doSomething({ arg1: 'a', arg2: 'b', arg3: 'c' });
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Just create an object and then assign it as default paramter:

const defaultParam = {
  arg1: "foo",
  arg2: "bar"
};

function doSomething({...parameter}) {
  console.log(parameter);
}

doSomething({arg3: "Hello"});
doSomething({...defaultParam, arg1: "New dude!", arg3: "Hello"});
FisNaN
  • 2,517
  • 2
  • 24
  • 39
  • I don't think this actually works. If the user passes anything in the first argument, then `parameter` will not end up with your default `arg1`, and `arg2` values. – user3056556 Apr 04 '18 at 07:31
  • @user3056556 I see, didn't get exactly what you want in the first place. I updated my answer. This should work – FisNaN Apr 04 '18 at 07:43