2010-07-29 17 views
8

tengo el siguiente "enumeración" en javascript para indicar el estado de mi solicitud:Javascript enumeración dentro de una enumeración

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

Ahora, quiero que cada estado tiene un "sub-estado". 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" State? Gracias

Si hay una mejor manera de estructurar esto en total (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.

+0

Si tiene algo configurado en STATE_B2, ¿quiere que la comparación con STATE_B sea cierta también? – EndangeredMassa

+0

EndangeredMassa - sí, lo hago, gracias por aclarar – aeq

+0

Pensamiento aleatorio: algunas respuestas aparecen con objetos, pero ¿abordan el STATE_B === 1 así como el STATE_B.B1 === 1? –

Respuesta

2

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

Para responder a su pregunta, sí, totalmente Puede anidar objetos:

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

A continuación, sólo tiene que utilizar la notación de puntos con el fin de establecer esos valores, como

State.State_B.SUBSTATE_2 = "active".

+0

También me gustaría una evaluación de State.State_B.SUBSTATE_2 == State.State_B para evaluar a verdadero. ¿Alguna idea sobre cómo lograr esto? – aeq

+1

@aeq: Esa comparación nunca será cierta a menos que 'SUBSTATE_2' y' State_B' sean los mismos objetos. – casablanca

0

supongo que quiere escribir algo así como

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

puede simplemente definir otra capa en su objeto Estado como

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

Editar: En base a 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 se puede llamar 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. 
+0

Estaba confundido por un tiempo con mis comentarios anteriores. Pero diga que el estado es State.STATE_B.B1: quiero un cheque para State.STATE_B para evaluar a verdadero. ¿Cómo puedo lograr esto? Gracias. – aeq

+0

@aeq Vea la parte después de la nota. Aunque ya no puedes evaluar con '===', pero tendrías que usar el método 'check (value)'. – moxn

5

Se podría utilizar algún tipo de campo de bits si 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"); 
} 

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

+0

+1 Me gusta esto. – moxn

0

Dado que JavaScript no es compatible con la sobrecarga del operador, no se puede probar directamente la igualdad de subestados utilizando el operador ==.Lo más cerca que se puede obtener es utilizar el operador instanceof para comprobar 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 puesto que las funciones son también objetos, puede agregar su anidación a la derecha en la función 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 comprobar 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 
+0

Usando 'instaceof' ... Ew :) – TheCloudlessSky

+0

@TheCloudlessSky: Bueno, eso es lo más cercano a la comparación que puedes obtener ... :) – casablanca

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