3

I'm spinning my head around this for a little while, but it seems I can't manage to make this work the way I would like it to. Actually, all I want here is to have nested default values for an optional argument. The output I'd like to see should be:

55, 44, { sub1: '0', sub2: 55, sub3: 'all'}

Instead, I just get this:

55, 44, { sub2: 55 }

Could somebody give me a heads up on this one?

function foo({ param1=55, param2=44, param3:param3 = { sub1:sub1='0', sub2:sub2=200, sub3:sub3='all' } } = { }) {
  console.log(param1, param2, param3);
}

foo({
  param3: {
    sub2: 55
  }
});
jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 2
    Doesn't the default value only get applied if nothing is passed into that parameter? I'm pretty sure it doesn't run something like `Object.assign` – Rob M. Aug 29 '17 at 21:41
  • If you just skip `param3` the whole default object gets into play. I honestly don't know if you even can go for nested default values like this, can't find much about it. – jAndy Aug 29 '17 at 21:43

2 Answers2

6

You are passing {sub2: 55} for param3, so it will not evaluate the default value { sub1:sub1='0', sub2:sub2=200, sub3:sub3='all' } (which is a literal here, not an assignment target, so wouldn't do what you think it does anyway).

If you want param3 to always be an object with 3 properties, constructed from the three default-valued variables, you have to build it explicitly yourself:

function foo({param1=55, param2=44, param3: {sub1='0', sub2=200, sub3='all'} = {}} = {}) {
  var param3 = {sub1, sub2, sub3};
  console.log(param1, param2, param3);
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • In other words, there is no way to create default values for nested destructured arguments? – jAndy Aug 29 '17 at 21:44
  • @jAndy Not sure what you mean. You can nest argument destructuring arbitrarily, and put default values on every level. What you cannot do is have destructuring mutate arguments or create new objects whose parts are made from defaulted values. – Bergi Aug 29 '17 at 21:48
  • So, if you pass `param3` in this example, it will always overwrite the entire object right? The point I'm wondering is, if you can again create default values within that passed object (it's basically the same thing as on the outside, just nested). But it seems you already gave the answer to that question. I'd like to have that feature anyways. – jAndy Aug 29 '17 at 21:51
  • 1
    @jAndy Yes, if there is a value it gets assigned to the target and the default initialiser is not evaluated. Whether the target is another destructuring, or a variable, does not matter. See [here](https://stackoverflow.com/a/43903662/1048572) for more explanation. – Bergi Aug 29 '17 at 21:57
0

Default parameters only get assigned if the parameter is empty. I think you need to use Object.assign in the body of the function:

const defaults = { sub1:sub1='0', sub2:sub2=200, sub3:sub3='all' }
function foo({ param1=55, param2=44, param3 } = { }) {
  const myParam3 = Object.assign({}, defaults, param3);
  console.log(param1, param2, myParam3);
}

foo({
  param3: {
    sub2: 55
  }
});
Rob M.
  • 35,491
  • 6
  • 51
  • 50
  • You don't need `param3:param3 = defaults`, just `param3` would be enough. Then you can also inline the `defaults` in the `Object.assign` call, and merge it with the first object literal. – Bergi Aug 29 '17 at 22:06