0

I'm trying to default options in ES7 using babel. Here is what I can do:

class Foo {
  constructor({key='value', foo='bar', answer=42}) {
    this.key = key; 
    this.foo = foo;
    this.number = number;
  }
}

This might work for this example, but I would like to know how can I assign for very large config objects; here is an example of what I wanna do:

class Foo {
  constructor(opts = {key='value', foo='bar', answer=42}) {
    this.opts = opts;
  }
}

However this does not compile. I tried to do it like this:

class Foo {
  constructor(opts = {key:'value', foo:'bar', answer:42}) {
    this.opts = opts;
  }
}

But then it replaces the whole object, like this:

let foo = new Foo({key: 'foobar'});

console.log(foo.opts);
// {key: 'foobar'} is what is displayed
// When I want {key: 'foobar', foo:'bar', answer:42}
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Vinz243
  • 9,654
  • 10
  • 42
  • 86

2 Answers2

2

It is

class Foo {
  constructor({key='value', foo='bar', answer=42} = {}) {
    ...
  }
}

It is ES6 destructuring feature, not specific to ECMAScript 7 (ECMAScript Next) proposals.

Without destructuring it is usually done with object cloning/merging, Object.assign comes to help:

class Foo {
  constructor(opts = {}) {
    this.opts = Object.assign({
      key: 'value',
      foo: 'bar',
      answer: 42
    }, opts);
  }
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Sorry, I realized my post wasn't really clear. So I edited the title. I don't want to destructurate my parameter – Vinz243 Jan 29 '17 at 13:33
  • Without destructuring you have to copy the objects manually. I've updated the answer with recipe which I usually use for that. – Estus Flask Jan 29 '17 at 13:39
  • That's what I ended up to do in the end I just wanted to know if I could do it with ES6/7. Thanks! – Vinz243 Jan 29 '17 at 13:51
  • 1
    You're welcome. No, it's the way how it is done. If `opts` isn't used for anything else, `opts = {}` can be just `opts` because `Object.assign` allows `undefined`. `Object.assign` is already [quite ES6-ish](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Specifications). – Estus Flask Jan 29 '17 at 13:55
2

I don't think you can do this with ES6 optional parameters (object as a parameter with optional keys), because when you call the constructor, it's a new object with a new reference. That's because it's being replaced.

But, as a suggestion, if you want to handle a large options object, one common approach is store somewhere a default options Object and merge the object with the one passed when you instantiate it.

Something like that:

class Foo {

  constructor(opts) {
    this.opts = Object.assign({}, Foo.defaultOptions, opts)
    console.log(this.opts)
  }
}

Foo.defaultOptions = {
    key: 'value', 
    foo: 'bar',
    answer: 42
}

let foo = new Foo({key: 'another value'})
//{ key: 'another value', foo: 'bar', answer: 42 }

You can merge with Object.assign (be aware that it does not perform deep merging - nested objects are replaced).

Or, if you want to declare your default options Object as a class variable (not at the end, after class declaration, or inside constructor), as you're using babel, you can use this plugin and do this:

class Foo {

    defaultOptions = {
        key: 'value', 
        foo: 'bar',
        answer: 42
    }

    constructor(opts) {
        this.opts = Object.assign({}, this.defaultOptions, opts)
        console.log(this.opts)
    }
}

It's more readable.

mrlew
  • 7,078
  • 3
  • 25
  • 28