Javascript enum в enum - PullRequest
       6

Javascript enum в enum

8 голосов
/ 29 июля 2010

У меня есть следующее «Enum» в javascript, чтобы указать состояние моего приложения:

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

Теперь я хочу, чтобы в каждом штате было «подсостояние». Так, например, STATE_B может быть в STATE_B1 или STATE_B2 ...

Как лучше всего это структурировать? Буду ли я как-то вкладывать «enum» в «enum» State? Спасибо

Если есть лучший способ структурировать это вообще (кроме перечислений), я весь в ушах. По сути, мне нужно иметь возможность устанавливать и проверять состояние моего приложения, и к каждому состоянию может (но не обязательно) присоединяться подсостояние, которое можно устанавливать и проверять. Еще лучше, если решение позволит мне пройти более 1 уровня глубины вложения.

Ответы [ 5 ]

5 голосов
/ 29 июля 2010

Вы можете использовать какое-то битовое поле, если хотите:

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

Таким образом, первые 8 бит зарезервированы для установки подсостояния. Конечно, вы можете увеличить это, если корневое состояние и подсостояние могут помещаться в 32-разрядном целом числе. Если вам нужно объяснить, почему / как это работает (побитовые операторы), дайте мне знать.

2 голосов
/ 29 июля 2010

То, что вы делаете, на самом деле не перечисляется.Вы используете нативные объекты Javascript и просто обрабатываете их как перечисления, что совершенно приемлемо, если вы хотите, чтобы в Javascript был объект, подобный перечислению.

Чтобы ответить на ваш вопрос, да, вы можете полностью вкладывать объекты:

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

Затем вы просто используете точечную запись, чтобы установить эти значения, например

State.State_B.SUBSTATE_2 = "active".

0 голосов
/ 29 июля 2010
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
0 голосов
/ 29 июля 2010

Поскольку JavaScript не поддерживает перегрузку операторов, вы не можете напрямую проверить на равенство подсостояний, используя оператор ==. Самое близкое, что вы можете получить, это использовать оператор instanceof, чтобы проверить, является ли состояние заданного типа, например:

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

И поскольку функции также являются объектами, вы можете добавить свое вложение прямо в функцию 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();

И проверьте его тип:

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 голосов
/ 29 июля 2010

Полагаю, вы хотите написать что-то вроде

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

Вы можете просто определить другой слой в вашем объекте State, например

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

Редактировать : Основываясь на комментариях к вашему вопросу, можно использовать другой подход.

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

Теперь вы можете звонить как угодно с помощью

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...