2

Given an ES6 class as follows, what is the best way to keep a reference to the data passed into the constructor so it is available from instance methods?

The best I've found so far is to manually add a reference to each one to some instance property within the constructor. Is there a cleaner/easier way?

class Test {

  constructor( {
    option1 = 1,
    option2 = 2
  } = {} ) {

    // What's the best way to keep a reference to
    // the options on the instance?
    this.options = {
      option1,
      option2
    };
  }

  addOptions() {
    return this.options.option1 + this.options.option2;
  }
}

let t = new Test({
  option1: 5
});

console.log(t.addOptions()); // 7

Here's a link to the above code running via 6to5.

James Allardice
  • 164,175
  • 21
  • 332
  • 312

2 Answers2

2

ES6 doesn't allow prototype properties to be declared within class declarations which is a bit of pain... However, using a getter to return defaults may be good for your situation. Perhaps try something like this:

class Test {
  get defaults() { return { option1: 1, option2: 2 }; }

  constructor(parameters) {
    this.options = Object.assign({}, this.defaults, parameters)
  }

  doSomething() {
    return this.options.option1 + this.options.option2;
  }
}

let test = new Test({
  option1: 5
});

console.log(test.doSomething());

Here is a link to the above code running on 6to5 REPL. If you want an example of merging defaults with inheritance, take a look at the constructor of this class.

Andrew Odri
  • 8,868
  • 5
  • 46
  • 55
  • *"ES6 doesn't allow instance properties"* Uh? What is `this.options` then? – Felix Kling Feb 13 '15 at 05:52
  • 2
    @FelixKling Ahh, I should have been a little clearer; ES6 doesn't allow prototype properties to be declared within class declaration: http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes – Andrew Odri Feb 13 '15 at 06:42
  • @AndrewOdri - Thanks, there's some nice ideas here and within that tungstenjs repo you linked to. Like you mentioned it's somewhat annoying that the new class declaration syntax doesn't allow for instance methods. I've never been entirely sure why but apparently it was [explicitly decided against](https://stackoverflow.com/questions/22528967/es6-class-variable-alternatives). – James Allardice Feb 13 '15 at 09:43
  • @JamesAllardice Yeah; a good discussion of the reasons why are found here: http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives I suspect the real reasons are that it would be more of a simulation of classical inheritance rather than staying true to prototypal inheritance, and that too much of a sudden change might confused developers not familiar with ES6. Hopefully ES7 will change some of these behaviors... – Andrew Odri Feb 13 '15 at 17:51
0

Since you are destructuring the first argument and have no named reference for it, how about this.options = arguments[0]?

If you don't want external functions to modify it you could deep-freeze it.

If you want it to be inaccessible use an instance-keyed WeakMap in the module's scope to hide them.

To get default values you can use this instead:

const defaults = {...}

function(options) {
  this.options = Object.assign({}, defaults, options)
  // now destructure to local vars as needed
  ...
}

Beware: Object.assign is just a shallow merge.

the8472
  • 40,999
  • 5
  • 70
  • 122
  • The object in `arguments[0]` doesn't seem to get an e.g. `option2` property if the default value is used instead of being passed in. Otherwise this would work. Alternatively, is there a cleaner way to provide default values for an object argument without destructuring it? – James Allardice Feb 12 '15 at 16:38