10

I have the following "Enum" in javascript to indicate the state of my application:

var State = { STATE_A: 0, STATE_B: 1, STATE_C: 2 //... } 

Now, I want each state to have a "sub-state". So for example, STATE_B could be in STATE_B1 or STATE_B2 ...

What would be the best way to structure this? Would I somehow nest an "enum" within the State "enum" ? Thanks

If there is a better way to structure this altogether (other than enums) I'm all ears. Basically I need to be able to set and check the state of my application, and each state can (but not necessary) have a sub-state attached to it which can be set and checked. Even better if the solution allows me to go more than 1 level of nesting deep.

5
  • If you have something set to STATE_B2, do you want a comparison to STATE_B to be true as well? Commented Jul 29, 2010 at 13:35
  • EndangeredMassa - yes absolutely I do, thanks for clarifying Commented Jul 29, 2010 at 13:37
  • Random thought: Some answers popping up with objects, but do they address the STATE_B === 1 as well as the STATE_B.B1 === 1? Commented Jul 29, 2010 at 13:46
  • back to EndangeredMassas point (after thinking about it, it turned out to be a very important question): I do, in fact, want this comparison to be true. I don't think the solutions below allow for this though. any ideas? Commented Jul 29, 2010 at 13:55
  • The answer I provided should be able to do what you'd like. Commented Jul 29, 2010 at 14:34

5 Answers 5

7

What you're doing isn't really enums. You're using native Javascript objects and just treating them like enums, which is perfectly acceptable when you want an enum-like object in Javascript.

To answer your question, yes, you can totally nest objects:

var State = { STATE_A: 0, STATE_B:{ SUBSTATE_1 : "active", SUBSTATE_2 : "inactive" }, STATE_C: 2 //... } 

You then just use the dot notation in order to set those values, like

State.State_B.SUBSTATE_2 = "active".

Sign up to request clarification or add additional context in comments.

2 Comments

I'd also like an evaluation of State.State_B.SUBSTATE_2 == State.State_B to evaluate to true. Any ideas on how to accomplish this?
@aeq: That comparison will never be true unless SUBSTATE_2 and State_B are the same objects.
5

You could use some sort of bit-field if you want:

var State = function() { // Note this must increment in powers of 2. var subStates = 8; var A = 1 << subStates; var B = 2 << subStates; var C = 4 << subStates; var D = 8 << subStates; return { // A // Note this must increment in powers of 2. STATE_A: A, STATE_A1: A | 1, STATE_A2: A | 2, STATE_A3: A | 4, STATE_A4: A | 8, STATE_A5: A | 16 // B STATE_B: B, STATE_B1: B | 1, // C STATE_C: C, STATE_C1: C | 1, STATE_C2: C | 2, STATE_C3: C | 4, STATE_C4: C | 8, // D STATE_D: D }; }(); // Set a state. var x = State.STATE_A1; // Same as State.STATE_A | State.STATE_A1 // Determine if x has root state of A? if(x & State.STATE_A == State.STATE_A) { console.log("Root state is A."); } else { console.log("Nope, not root state A."); } // Determine if x has sub-state A1? if(x & State.STATE_A1 == State.STATE_A1) { console.log("A with Substate 1"); } 

So the first 8 bits are reserved for setting the sub-state. You could, of course, increase this as long as the root-state and sub-state can fit inside a 32-bit integer. If you need explanation as to why/how this works (bit-wise operators), let me know.

Comments

0

I guess you want to write something like

if (State.STATE_A === someState) { ... } 

You could simply define another layer in your State object like

var State = { STATE_A : 0 STATE_B : { B1 : 1, B2 : 2, } }; ... if (State.STATE_B.B1 == someState){...} 

Edit: Based on the comments on your question another approach could be this.

//Creates state objects from you json. function createStates(json) { var result = {}; for(var key in json) { result[key] = new State(json[key]); } return result; } //State class function State(value) { //If the state value is an atomic type, we can do a simple comparison. if (typeof value !== "object") { this.value = value; this.check = function(comp){ return value === comp; }; } // Or else we have more substates and need to check all substates else if (typeof value === "object") { this.value = createStates(value); for(var key in this.value) { //Allows to access StateA.SubStateA1. Could really mess things up :( this[key] = this.value[key]; } this.check = function(comp){ for(var key in this.value) { if (this.value[key].check(comp) === true){ return true; } } return false; }; } }; 

Now you can call everything with

var stateJson = { STATE_A : 0, STATE_B : { B1 : 1, B2 : 2 } }; var states = createStates(stateJson); alert(states.stateA.check(0)); // Should give true alert(states.STATE_B.B1.check(1)); // Same here alert(states.STATE_B.check(1)); //And again because value is valid for one of the substates. 

2 Comments

I was confused for a while with my comments above. But say the state is State.STATE_B.B1: I do want a check for State.STATE_B to evaluate to true. How can I accomplish this? Thanks.
@aeq See the part after the note. Though you cannot evaluate with === anymore, but would have to use the check(value) method.
0

Since JavaScript does not support operator overloading, you cannot directly test for equality of substates using the == operator. The closest you can get is to use the instanceof operator to check if a state is of a given type, for example:

// All these functions are empty because we only need the type and there is no data function State() { } function State_A() { } State_A.prototype = new State(); function State_B() { } State_B.prototype = new State(); function State_B1() { } State_B1.prototype = new State_B(); function State_B2() { } State_B2.prototype = new State_B(); 

And since functions are also objects, you can add your nesting right into the State function:

State.STATE_A = new State_A(); State.STATE_B = new State_B(); State.STATE_B.STATE_B1 = new State_B1(); State.STATE_B.STATE_B2 = new State_B2(); 

And check its type:

var myState = State.STATE_B1; myState instanceof State // true myState instanceof State_A // false myState instanceof State_B // true myState instanceof State_B1 // true 

1 Comment

@TheCloudlessSky: Well, that's as close to comparison as you can get... :)
0
function State () { this.superState = null; } State.prototype = { constructor: State , mkSubState () { var subState = new State (); subState.superState = this; return subState; } , isSubStateOf (superState) { var state = this; while (state !== null) { if (this.superState === superState) { return true; } state = this.superState; } return false; } , isSuperStateOf (subState) { while (subState !== null) { if (subState.superState === this) { return true; } subState = subState.superState; } return false; } }; 

var States = {}; States.A = new State (); States.A1 = States.A.mkSubState (); States.A2 = States.A1.mkSubState (); States.B = new State (); States.B1 = States.B.mkSubState (); States.B2 = States.B1.mkSubState (); States.B2.isSubStateOf (B); // true States.B2.isSubStateOf (B1); // true States.B2.isSubStateOf (B2); // false States.B2.isSubStateOf (A); // false States.B2.isSubStateOf (A1); // false States.B2.isSubStateOf (A2); // false 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.