36

Is it possible to use destructuring assignment in a JavaScript class' constructor to assign the instance variables similar to how you can do it to normal variables?

The following example works:

var options = {one: 1, two: 2};
var {one, two} = options;
console.log(one) //=> 1
console.log(two) //=> 2

But I cannot get something like the following to work:

class Foo {
  constructor(options) {
    {this.one, this.two} = options;
    // This doesn't parse correctly and wrapping in parentheses doesn't help
  }
}

var foo = new Foo({one: 1, two: 2});
console.log(foo.one) //=> I want this to output 1
console.log(foo.two) //=> I want this to output 2
Prashant Ghimire
  • 4,890
  • 3
  • 35
  • 46
Aaron
  • 13,349
  • 11
  • 66
  • 105
  • 2
    I think the more general question is whether there's a destructuring assignment form that provides for creating properties on an existing object instead of an object initializer. – Pointy Jun 30 '16 at 15:29
  • 1
    Anyway there's always `Object.assign(this, options);` – Pointy Jun 30 '16 at 15:29
  • 1
    It's worth mentioning that you can apply the same syntax outside of constructors as well. Given are two objects: `let o = {a: 1, b: 2}, p = {};`. Deconstruct `o` to a less complex `p` is a peace of cake: `({b: p.b} = o);` yields `Object {b: 2}` for `p`. –  Jun 30 '16 at 16:23
  • Does this answer your question? [object destructuring without var](https://stackoverflow.com/questions/27386234/object-destructuring-without-var) – user202729 Jan 18 '21 at 01:04

2 Answers2

65

There are multiple ways of doing this. The first one uses destructuring only and assigns the properties of options to properties on this:

class Foo {
  constructor(options) {
    ({one: this.one, two: this.two} = options);
    // Do something else with the other options here
  }
}

The extra parentheses are needed, otherwise the JS engine might mistake the { ... } for an object literal or a block statement.

The second one uses Object.assign and destructuring:

class Foo {
  constructor(options) {
    const {one, two} = options;
    Object.assign(this, {one, two});
    // Do something else with the other options here
  }
}

If you want to apply all your options to the instance, you could use Object.assign without destructuring:

class Foo {
  constructor(options) {
    Object.assign(this, options);
  }
}
nils
  • 25,734
  • 5
  • 70
  • 79
  • 1
    Thanks @nils! This is exactly what I was looking for. The first solution is the most concise and uses a slightly more advanced destructuring that you'd either already know about or quickly figure out when reading/running the code. The 2nd is the clearest and most obvious while the 3rd is great for the use case you outlined. – Aaron Jun 30 '16 at 18:48
3

In addition to Nils´s answer. It also works with object spread (...)

class Foo {

  constructor(options = {}) {
    ({
      one: this.one,
      two: this.two,
      ...this.rest
    } = options);
  }
}

let foo = new Foo({one: 1,two: 2,three: 3,four: 4});

console.log(foo.one);  // 1
console.log(foo.two);  // 2
console.log(foo.rest); // {three: 3, four: 4}

... and/or custom settters for further processing

class Foo {

    constructor(options = {}) {
        ({
            one: this.one,
            two: this.two,
            ...this.rest
        } = options);
    }
   
    set rest(options = {}) {
        ({
          three: this.three,
          ...this.more
        } = options);
    }
}

let foo = new Foo({one: 1,two: 2,three: 3,four: 4});

console.log(foo.one);   // 1
console.log(foo.two);   // 2
console.log(foo.three); // 3
console.log(foo.more);  // {four: 4}
Exodus 4D
  • 2,207
  • 2
  • 16
  • 19