user3056556
user3056556

Reputation: 81

Destructuring and re-structuring in function arguments?

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.

Upvotes: 8

Views: 631

Answers (3)

Steve Harrison
Steve Harrison

Reputation: 125510

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;
}

Upvotes: 3

FisNaN
FisNaN

Reputation: 2865

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"});

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386600

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' });

Upvotes: 0

Related Questions