0

const Color = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',

  values: [this.RED, this.GREEN, this.BLUE],

  allValues() {
    return [this.RED, this.GREEN, this.BLUE]
  }
}

console.log(Color.values); // [undefined, undefined, undefined]
console.log(Color.allValues()); // ["red", "green", "blue"]

I recently started learning about javascript and this is tripping me up, I would consider making it work by wrapping it up in a function hacky and would really like to avoid doing that. What am I doing wrong here?

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
Edward Lim
  • 763
  • 9
  • 31
  • 2
    "You can't reference an object during initialization when using object literal syntax. You need to reference the object after it is created." See the link above. – Akrion Jul 29 '18 at 07:12
  • [Great Article to understand Javascript Context/This](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/) – cheekujha Jul 29 '18 at 07:15

2 Answers2

4

This is not possible within an object literal. While creating the Object instance from the literal this is not yet available. You can create and instantaneous use something to initialize the values, or use a getter for the values property (see @James answer for that) though:

// initialization
const Color = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',
  init() {
    this.values = [this.RED, this.GREEN, this.BLUE];
    return this;
  }
}.init();

console.log(Color.values);

Just for fun: if you want to rule out the use of this completely, this (pun intended;) would be es20xx alternatives:

const Color = Object.entries({
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue'})
  .reduce( (o, [key, value]) => 
    ( o.values.push(value), {...o, [key]: value} ), {values: []} );
  
console.log(Color.values);

// Or using this utility method
const objWithValues = o => 
    ({...o, values: Object.entries(o).map(([key, value]) => value) });
const Color2 = objWithValues({
    RED: 'red',
    GREEN: 'green',
    BLUE: 'blue'});

console.log(Color2.values);
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • Hmm the initialize approach is an interesting one, it solves the problem of creating an array everytime the values() func is called. Since i am new to JS what is the norm here? Is it acceptable to use getters in these scenarios since there is a built in way to do this? – Edward Lim Jul 29 '18 at 07:26
  • Personally I'd use a getter in this situation. Only in more complex situations or with huge data sizes the initialization may be more efficient and/or convenient. – KooiInc Jul 29 '18 at 07:29
  • 2
    Hmm... seems like this answer was edited to basically include mine, oh well. – James Jul 29 '18 at 07:38
  • @James: sorry, I constructed my answer is steps – KooiInc Jul 29 '18 at 11:12
  • Not sure I buy that tbh, your first answer was a definite "this can't be done" and offered the first solution as a workaround, to then minutes later "you can use a getter" - surely you seen my answer after you posted? It was posted at pretty much the same time. It's irrelevant now but not a fan of the whole reworking answers when it's already been suggested. – James Jul 29 '18 at 12:50
  • My answers often are not final in one go, I try to come up with alternatives if can think of them. Sometimes it takes a bit of time to try it out. In this case I offered 4 alternatives, one of which is using a getter. And no, the getter version was not specifically copied from your anwer - but hey, you don't _have_ to buy that. – KooiInc Jul 29 '18 at 13:15
3

To answer the question, this can be done via a getter

const Color = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',

  get values() {
    return [this.RED, this.GREEN, this.BLUE]
  }
}
...
console.log(Color.values); // ['red', 'green', 'blue']
James
  • 80,725
  • 18
  • 167
  • 237