11

I am trying to define a Javascript class with a defined constructor with params with the most proper ES6 syntax. At first, it is easy to define it like this.

let param1 = 10;
let param2 = 'foo';
let param3 = 200;
let param4 = 'bar';

let props = {id: param1, options: { op1: param2, op2: param3, op3: param4 }};

console.log('Object props');
console.log(props);

class Test {
  
  constructor(props){
    this.id = props.id;
    this.options = props.options;
  }
  
}

let test1 = new Test(props);
console.log('Class test1');
console.log(test1.id);
console.log(test1.options.op2);

But when I try to use destructuring to define default values, for one of the params of the constructor (op2, a property of the nested object options),I am not able to make it work, while for the id property of the object I am able:

let param1 = 10;
let param2 = 'foo';
let param3 = 200;
let param4 = 'bar';

let props = {options: { op1: param2, op3: param4 }};

console.log('Object props');
console.log(props);

class Test {
  
  constructor({id = 'defaultId', options = { op2:'0'}} = {}){
    this.id = id;
    this.options = options;
  }
  
}

let test = new Test(props);
console.log('Class test');
console.log(test.id);
console.log(test.options);
console.log(test.options.op2);

What I should expect is that when debugging with console.log(test.options.op2) prints the default value set in the constructor, but instead I am gettting undefined.

Also I would like to know if is there any more proper ES6 syntax when defining javascript classes to initialize class params.

Dez
  • 5,702
  • 8
  • 42
  • 51

2 Answers2

19

But when I try to use destructuring to define default values

constructor({id = 'defaultId', options = { op2:'0'}} = {}){

for one of the params of the constructor (op2, a property of the nested object options), I am not able to make it work, while for the id property of the object I am able.

Default values only work on the single parameter/property level. If no argument or undefined is passed, {} will be used for the first parameter. If the object does not have an id property, 'defaultId' will be used. If the object does not have an options property, {op2:'0'} will be used. If you do pass an object with an options property, the default value will be ignored.

So if you want a default value for the op2 property of the object if no such property was found in the object, you need to use destructuring on the options object itself:

constructor({id = 'defaultId', options: {op1, op2 = '0', op3} = {}} = {}) {
    this.id = id;
    this.options = {op1, op2, op3};
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • And this is what my issue was. The lack of knowing of the need to destructure in every nested level, not just in the top level. – Dez Nov 22 '16 at 11:29
3

You can not actually add missing properties to an object as it's never added because options object does not fallback to default values. In this particaular scenario it would be much simplier to go this way:

class Test {

  constructor({id = 'defaultId', options= { op2:'0'}} = {}){
    this.id = id;
    this.options = options;
    this.options.op2 = this.options.op2 || '0';
  }

}
Alex Bykov
  • 718
  • 6
  • 13
  • 3
    Don't use `||` to set default value, see [What does the construct x = x || y mean?](http://stackoverflow.com/a/34707750/3853934) – Michał Perłakowski Nov 17 '16 at 15:49
  • @Alex Bykov if I understood you well, if what you state is true, in my second example the param `id` wouldn't get the default value assigned rightly, as it is being done as expected, because it is missing from the object `props` – Dez Nov 17 '16 at 16:59