2010-07-29 16 views
8

Ho la seguente "Enum" in javascript per indicare lo stato della mia domanda:Javascript enum all'interno di un enum

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

Ora, voglio ogni stato di avere un "sub-stato". Ad esempio, STATE_B potrebbe essere in STATE_B1 o STATE_B2 ...

Quale sarebbe il modo migliore per strutturarlo? Dovrei in qualche modo annidare un "enum" all'interno dello "enum" State? Grazie

Se c'è un modo migliore per strutturare questo insieme (oltre alle enumerazioni), io sono tutto orecchie. Fondamentalmente ho bisogno di essere in grado di impostare e controllare lo stato della mia applicazione, e ogni stato può (ma non necessario) avere un sotto-stato ad esso allegato che può essere impostato e controllato. Ancora meglio se la soluzione mi consente di andare più di 1 livello di nidificazione in profondità.

+0

Se hai qualcosa impostato su STATE_B2, vuoi che anche un confronto con STATE_B sia vero? – EndangeredMassa

+0

EndangeredMassa - sì assolutamente sì, grazie per aver chiarito il numero – aeq

+0

Pensiero casuale: alcune risposte stanno spuntando con gli oggetti, ma affrontano lo STATE_B === 1 e lo STATE_B.B1 === 1? –

risposta

2

Quello che stai facendo non è davvero enumerazione. Stai usando oggetti Javascript nativi e li tratti come enumerazioni, il che è perfettamente accettabile quando vuoi un oggetto simile a enum in Javascript.

Per rispondere alla tua domanda, sì, si può assolutamente oggetti nido:

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

È poi basta usare la notazione punto, al fine di impostare questi valori, come

State.State_B.SUBSTATE_2 = "active".

+0

Mi piacerebbe anche una valutazione di State.State_B.SUBSTATE_2 == State.State_B per valutare su true. Qualche idea su come realizzare questo? – aeq

+1

@aeq: quel confronto non sarà mai vero a meno che 'SUBSTATE_2' e' State_B' siano gli stessi oggetti. – casablanca

0

Credo che si vuole scrivere qualcosa di simile a

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

Si potrebbe semplicemente definire un altro livello nel vostro oggetto Stato come

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

Edit: Sulla base delle osservazioni sulla tua domanda un altro approccio potrebbe essere questo

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

Ora è possibile chiamare tutto 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

Sono stato confuso per un po 'con i miei commenti sopra. Ma dire che lo stato è State.STATE_B.B1: Voglio un controllo per State.STATE_B per valutare su true. Come posso realizzare questo? Grazie. – aeq

+0

@aeq Vedi la parte dopo la nota. Anche se non puoi più valutare con '===', ma dovresti usare il metodo 'check (valore)'. – moxn

5

Si potrebbe utilizzare una sorta di campo di bit se si desidera:

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

Così i primi 8 bit sono riservati per l'impostazione sub-stato. Potresti, naturalmente, aumentare questo finché lo stato-radice e il sotto-stato possono rientrare in un numero intero a 32-bit. Se hai bisogno di spiegazioni sul perché/come funziona (operatori bit-saggio), fammi sapere.

+0

+1 Mi piace. – moxn

0

Poiché JavaScript non supporta l'overloading dell'operatore, non è possibile testare direttamente l'uguaglianza dei substati utilizzando l'operatore ==.Il più vicino si può arrivare è quello di utilizzare l'operatore instanceof per verificare se uno Stato è di un certo tipo, ad esempio:

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

E poiché le funzioni sono oggetti anche, puoi aggiungere la tua nidificazione destra nella funzione 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(); 

E controllare il suo 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

Uso di 'instaceof' ... Ew :) – TheCloudlessSky

+0

@TheCloudlessSky: Beh, questo è il paragone più vicino possibile ... :) – 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