Javascript enum dentro de una enumeración

Tengo el siguiente "Enum" en javascript para indicar el estado de mi aplicación:

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

Ahora, quiero que cada estado tenga un "subestado". Entonces, por ejemplo, STATE_B podría estar en STATE_B1 o STATE_B2

¿Cuál sería la mejor manera de estructurar esto? ¿De alguna manera anidaría una "enumeración" dentro de la "enumeración" del estado? Gracias

Si hay una mejor manera de estructurar esto por completo (aparte de enums) soy todo oídos. Básicamente, necesito poder establecer y verificar el estado de mi aplicación, y cada estado puede (pero no es necesario) tener un subestado adjunto que se puede configurar y verificar. Aún mejor si la solución me permite ir más allá de un nivel de anidamiento profundo.

Lo que estás haciendo no es realmente enumeraciones. Está utilizando objects Javascript nativos y solo los trata como enumeraciones, lo cual es perfectamente aceptable cuando quiere un object similar a enum en Javascript.

Para responder a su pregunta, sí, puede anidar objects por completo:

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

Luego, simplemente usa la notación de puntos para establecer esos valores, como

State.State_B.SUBSTATE_2 = "active" .

Podría usar algún tipo de campo de bits si lo desea:

 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"); } 

Entonces, los primeros 8 bits están reservados para configurar el subestado. Podría, por supuesto, boost esto siempre que el estado raíz y el subestado puedan caber dentro de un integer de 32 bits. Si necesita una explicación de por qué / cómo funciona esto (operadores bit a bit), hágamelo saber.

Supongo que quieres escribir algo como

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

Simplemente podría definir otra capa en su object de Estado como

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

Editar : basado en los comentarios sobre su pregunta, otro enfoque podría ser esto.

 //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; }; } }; 

Ahora puedes llamar a todo con

 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. 

Como JavaScript no admite la sobrecarga del operador, no se puede probar directamente la igualdad de subestados utilizando el operador == . Lo más cercano que puede get es usar el operador instanceof para verificar si un estado es de un tipo dado, por ejemplo:

 // 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(); 

Y dado que las funciones también son objects, puede agregar su anidación directamente a la function State :

 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(); 

Y revisa su tipo:

 var myState = State.STATE_B1; myState instanceof State // true myState instanceof State_A // false myState instanceof State_B // true myState instanceof State_B1 // true 
 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