【问题标题】:Javascript enum within an enum枚举中的 Javascript 枚举
【发布时间】:2011-03-22 17:28:48
【问题描述】:

我在 javascript 中有以下“枚举”来指示我的应用程序的状态:

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

现在,我希望每个状态都有一个“子状态”。例如,STATE_B 可能在 STATE_B1STATE_B2 ...

构建这个的最佳方式是什么?我会以某种方式在 State "enum" 中嵌套一个“enum”吗?谢谢

如果有更好的方法来构建它(枚举除外),我会全力以赴。基本上我需要能够设置和检查我的应用程序的状态,并且每个状态都可以(但不是必需的)附加一个可以设置和检查的子状态。如果解决方案允许我进行超过 1 层的嵌套,那就更好了。

【问题讨论】:

  • 如果您将某些内容设置为 STATE_B2,您是否希望与 STATE_B 的比较也为真?
  • EndangeredMassa - 是的,我愿意,感谢您的澄清
  • 随机思考:一些答案随着对象弹出,但它们是否针对 STATE_B === 1 以及 STATE_B.B1 === 1?
  • 回到 EndangeredMassas 的观点(经过思考,这是一个非常重要的问题):事实上,我确实希望这个比较是真实的。我认为下面的解决方案不允许这样做。有什么想法吗?
  • 我提供的答案应该可以为所欲为。

标签: javascript enums


【解决方案1】:

您所做的并不是真正的枚举。您正在使用本机 Javascript 对象并将它们视为枚举,当您想要在 Javascript 中使用类似枚举的对象时,这是完全可以接受的。

回答你的问题,是的,你可以完全嵌套对象:

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

然后您只需使用点符号来设置这些值,例如

State.State_B.SUBSTATE_2 = "active".

【讨论】:

  • 我还希望对 State.State_B.SUBSTATE_2 == State.State_B 进行评估以评估为真。关于如何做到这一点的任何想法?
  • @aeq:除非SUBSTATE_2State_B 是同一个对象,否则这种比较永远不会成立。
【解决方案2】:

如果你愿意,你可以使用某种位域:

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 位整数内,您就可以增加此值。如果您需要解释为什么/如何工作(按位运算符),请告诉我。

【讨论】:

    【解决方案3】:

    我猜你想写类似的东西

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

    您可以简单地在 State 对象中定义另一个层,例如

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

    编辑:根据您问题的 cmets,另一种方法可能是这样。

    //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.
    

    【讨论】:

    • 我对上面的 cmets 感到困惑了一段时间。但是说状态是 State.STATE_B.B1:我确实想要检查 State.STATE_B 以评估为真。我怎样才能做到这一点?谢谢。
    • @aeq 见注释后的部分。虽然您不能再使用=== 进行评估,但必须使用check(value) 方法。
    【解决方案4】:

    由于 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
    

    【讨论】:

    • @TheCloudlessSky:嗯,这是你能得到的最接近的比较...... :)
    【解决方案5】:
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-08
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 2017-11-10
      相关资源
      最近更新 更多