Search code examples
javascriptecmascript-6babeljsecmascript-2016

Named default ES6 parameter without destructuration


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}

Solution

  • 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.