I am trying to figure out if it is possible to handle multiple levels of default parameters with destructuring. Since it is not easy to explain with words, here is a step-by-step example...
1 - Flat object destructuring with default parameters
Destructuring this object is easy:
let obj = {
foo: 'Foo',
bar: 'Bar'
};
With {foo = 'Foo', bar = 'Bar'} = {} in a function signature, an object will be created if there is no argument passed when the function is called. If an object is passed but some referenced properties are undefined, they will be replaced by their default values. This code works fine:
function fn1({foo = 'Foo', bar = 'Bar'} = {}) {
console.log(foo, bar);
}
// OK
fn1(); // Foo Bar
fn1({foo: 'Quux'}); // Quux Bar
fn1({bar: 'Quux'}); // Foo Quux
fn1({foo: 'Quux', bar: 'Quux'}); // Quux Quux
2 - Nested object destructuring with shallow default parameters
Destructuring this object is harder:
let obj = {
foo: 'Foo',
bar: {
quux: 'Quux',
corge: 'Corge'
}
};
{foo = 'Foo', bar = 'Bar'} = {} is not a viable option anymore, but now we can use {foo = 'Foo', bar = {quux: 'Quux', corge: 'Corge'}} = {} in a function signature. Again, if no argument is given when the function is called, an object is created and the core properties (foo and bar) are extracted. If an object is passed, only undefined properties (foo or bar) will be destructured with their default values.
The problem is that the object properties of bar (quux and corge) are not part of the "top-level destructuring". This means quux or corge will be undefined if they are not explicitly set when bar is passed as an argument:
function fn2({foo = 'Foo', bar = {quux: 'Quux', corge: 'Corge'}} = {}) {
console.log(foo, bar.quux, bar.corge);
}
// OK
fn2(); // Foo Quux Corge
fn2({foo: 'Quux'}); // Quux Quux Corge
// Oops!
fn2({bar: {quux: 'Baz'}}); // Foo Baz undefined
fn2({foo: 'Quux', bar: {corge: 'Baz'}}); // Quux undefined Baz
3 - Nested object destructuring with deep default parameters
I would like to set default parameters at all levels of the object hierarchy to use a sort of "cascading destructuring". I tried this, but it does not work:
function fn3({foo = 'Foo', bar = ({quux = 'Quux', corge = 'Corge'} = {})} = {}) {
console.log(foo, bar.quux, bar.corge);
}
// Oops!
fn3(); // Foo undefined undefined
fn3({foo: 'Quux'}); // Quux undefined undefined
fn3({bar: {quux: 'Baz'}}); // Foo Baz undefined
fn3({foo: 'Quux', bar: {corge: 'Baz'}}); // Quux undefined Baz
Do you know if such a feature is allowed in ES6. If yes, how can I implement it?