1

question

How to set an object property value to its own variable name (during initialization if possible)?

eg

For example, to create a Enum (inside class AA) in Javascript:

class AA {
  static Color = {
    Red: 'Red', 
    Green: 'Green', 
    Blue: 'Blue', 
  }
}

I have to repeat the String name everytime.

Is there a simpler way to do this, something like eg:

class AA {
  static Color = {
    Red: this.currentProperty.name, 
    Green: this.currentProperty.name, 
    Blue: this.currentProperty.name, 
  }
}

requirements (not mandatory) & comments

  • Please make this As Simple As Possible (dont be complicated/cumbersome).

    • (The hardest requirement. It would be best in the form shown above (during initialization).
    • I may be a bit picky on this... (I know this is very subjective, and such thing may not even exist)
    • though, any other thoughts are still welcome)
  • The variable value & variable name can be refactored at the same time -- without the need to change them separately.

  • It doesnt have to be an Enum (-- this topic is not limited to Enum only, a normal object will do)

  • Try to use Es6+

  • Try to let Jsdoc able to recognize this as an Enum (maybe the use of @emun (?<)), (mainly for autocompletion / Type hint on Vscode)

  • Try to let Debugger able to recognize this as an Enum & able to view the value as a meaningful string

  • Im aware of there are some Enum lib in github eg, not sure they are good enough / fit my style.

  • Im aware of the use of Symbol() on Enum

  • Im aware of need to make Enum immutable (private + getter / Object.freeze)

  • I dont think Object.keys() can help. (too cumbersome?)

Nor.Z
  • 555
  • 1
  • 5
  • 13
  • Why don't you think `Object.keys()` can help? I would loop over them and set each item to the key name. – mykaf Feb 09 '23 at 21:03
  • @mykaf It feels a little bit cumbersome -- isnt much better than: repeat the Strings / even just create a new `class Enum` myself for creating enums, I think? – Nor.Z Feb 09 '23 at 21:05
  • @mykaf or, is there a way to use `Object.keys()` inside the property, something like `Red: Object.keys(Color).Red` ? – Nor.Z Feb 09 '23 at 21:07
  • Not as far as I'm aware, because the Object hasn't actually been created yet. Will your object have many properties? – mykaf Feb 09 '23 at 21:29
  • @mykaf - > because the Object hasn't actually been created yet - that is what i think too. - The num of properties depends, normally 5~10. – Nor.Z Feb 09 '23 at 21:33
  • For 5-10 properties, I personally wouldn't worry about automating their values in this case. – mykaf Feb 09 '23 at 21:35

1 Answers1

2

class AA {
  static Color = Object.fromEntries(['Red','Green','Blue'].map(i=>[i,i]))
}
console.log(AA.Color)

or, with a helper method:

function makeEnum(...props) { return Object.fromEntries(props.map(i=>[i,i])) }

class AA {
   static Color = makeEnum('Red','Green','Blue')
}

console.log(AA.Color)

this might help with autocompletion:

function makeEnum(obj) { return Object.fromEntries(Object.keys(obj).map(i=>[i,i])) }

class AA {
   static Color = makeEnum({Red:'', Green:'', Blue:''})
}

console.log(AA.Color)

or using a proxy:

function makeEnum() {
  let o = {}, p = new Proxy(o, {get:(_,i)=>(i==='enum'?o:(o[i]=i,p))})
  return p
}

class AA {
  static Color = makeEnum().Red.Green.Blue.enum
}

console.log(AA.Color)

including Object.freeze() to prevent reassignment:

function makeEnum() {
  let o = {}, p = new Proxy(o, {get:(_,i)=>
    (i==='enum'?(Object.freeze(o),o):(o[i]=i,p))})
  return p
}

class AA {
  static Color = makeEnum().Red.Green.Blue.enum
}

console.log(AA.Color)
AA.Color.Red = 'Yellow'
console.log(AA.Color)

another proxy variant: the new keyword is used to trigger freezing of the object:

function Enum() {
  let o={}, p = new Proxy(function() {}, {
    construct: () => (Object.freeze(o),o),
    get:(_,i)=>(o[i]=i,p)
  });
  return p;
}

class AA {
  static Color = new (Enum().Red.Green.Blue)
}

console.log(AA.Color)
console.log(AA.Color.Red)
AA.Color.Red = 'Yellow' // frozen object can't be changed
console.log(AA.Color.Red)
AA.Color.Orange = 'Orange' // frozen object can't accept new properties
console.log(AA.Color)
Andrew Parks
  • 6,358
  • 2
  • 12
  • 27
  • - Looks good, let me try out. - Vscode autocompletion doesnt recognize the property inside though. – Nor.Z Feb 09 '23 at 21:11
  • @Nor.Z then I can't see a way of doing it without making a dummy object and filling in the values, as in the edited answer above – Andrew Parks Feb 09 '23 at 21:21
  • @Nor.Z actually maybe you might like the proxy approach I just updated the answer with – Andrew Parks Feb 09 '23 at 21:30
  • The proxy doesn't work. The value of `AA.Color.Red` is the proxy, not the string `Red`. – Barmar Feb 09 '23 at 21:32
  • @AndrewParks Proxy is very new to me. I will take a look. – Nor.Z Feb 09 '23 at 21:34
  • @Nor.Z I had to make a change to the proxy version. There is a need to do `.enum` at the end so that the real object is returned and not the proxy. This allows Object references to be compared directly, rather than doing string comparisons on what the object returns – Andrew Parks Feb 09 '23 at 21:38
  • - This is able to "set an object property value to its own variable name" - But I dont think autocompletion / Type hint works on this. And isnt as simple as I wanted. - Though its good to learn different ways of doing things. – Nor.Z Feb 09 '23 at 21:54
  • @Nor.Z one good thing is that, as you can see in the latest answer amendment, you can include Object.freeze() – Andrew Parks Feb 09 '23 at 22:00