以下内容是否会使对象满足枚举在JavaScript中的所有特性?类似于:

my.namespace.ColorEnum = {
  RED : 0,
  GREEN : 1,
  BLUE : 2
}

// later on

if(currentColor == my.namespace.ColorEnum.RED) {
  // whatever
}

还是有其他方法可以做到这一点?


当前回答

var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });

您不需要指定id,只需使用空对象来比较枚举即可。

if (incommingEnum === DaysEnum.monday) //incommingEnum is monday

EDIT:如果要序列化对象(例如JSON),将再次输入id。

(摘自加布里埃尔·利亚马斯评论)(根据Stijn de Witt的评论进行编辑)

其他回答

这是我对一个(标记的)Enum工厂的看法。这是一个工作演示。

/*
 * Notes: 
 * The proxy handler enables case insensitive property queries
 * BigInt is used to enable bitflag strings /w length > 52
*/
function EnumFactory() {
  const proxyfy = {
    construct(target, args) { 
      const caseInsensitiveHandler = { 
          get(target, key) {
          return target[key.toUpperCase()] || target[key];  
        } 
      };
      const proxified = new Proxy(new target(...args), caseInsensitiveHandler ); 
      return Object.freeze(proxified);
    },
  }
  const ProxiedEnumCtor = new Proxy(EnumCtor, proxyfy);
  const throwIf = (
      assertion = false, 
      message = `Unspecified error`, 
      ErrorType = Error ) => 
      assertion && (() => { throw new ErrorType(message); })();
  const hasFlag = (val, sub) => {
    throwIf(!val || !sub, "valueIn: missing parameters", RangeError);
    const andVal = (sub & val);
    return andVal !== BigInt(0) && andVal === val;
  };

  function EnumCtor(values) {
    throwIf(values.constructor !== Array || 
            values.length < 2 || 
        values.filter( v => v.constructor !== String ).length > 0,
      `EnumFactory: expected Array of at least 2 strings`, TypeError);
    const base = BigInt(1);
    this.NONE = BigInt(0);
    values.forEach( (v, i) => this[v.toUpperCase()] = base<<BigInt(i) );
  }

  EnumCtor.prototype = {
    get keys() { return Object.keys(this).slice(1); },
    subset(sub) {
      const arrayValues = this.keys;
      return new ProxiedEnumCtor(
        [...sub.toString(2)].reverse()
          .reduce( (acc, v, i) => ( +v < 1 ? acc : [...acc, arrayValues[i]] ), [] )
      );
    },
    getLabel(enumValue) {
      const tryLabel = Object.entries(this).find( value => value[1] === enumValue );
      return !enumValue || !tryLabel.length ? 
        "getLabel: no value parameter or value not in enum" :
        tryLabel.shift();
    },
    hasFlag(val, sub = this) { return hasFlag(val, sub); },
  };
  
  return arr => new ProxiedEnumCtor(arr);
}

真的很像@Duncan上面所做的,但我不喜欢用Enum破坏全局Object函数空间,所以我写了以下内容:

function mkenum_1()
{
  var o = new Object();
  var c = -1;
  var f = function(e, v) { Object.defineProperty(o, e, { value:v, writable:false, enumerable:true, configurable:true })};

  for (i in arguments) {
    var e = arguments[i];
    if ((!!e) & (e.constructor == Object))
      for (j in e)
        f(j, (c=e[j]));
    else
      f(e, ++c);
    }

  return Object.freeze ? Object.freeze(o) : o;
}

var Sizes = mkenum_1('SMALL','MEDIUM',{LARGE: 100},'XLARGE');

console.log("MED := " + Sizes.MEDIUM);
console.log("LRG := " + Sizes.LARGE);

// Output is:
// MED := 1
// LRG := 100

@Stijin也有一个简洁的解决方案(参考他的博客),其中包括这些对象的财产。我也为此写了一些代码,接下来我会把它包括在内。

function mkenum_2(seed)
{
    var p = {};

    console.log("Seed := " + seed);

    for (k in seed) {
        var v = seed[k];

        if (v instanceof Array)
            p[(seed[k]=v[0])] = { value: v[0], name: v[1], code: v[2] };
        else
            p[v] = { value: v, name: k.toLowerCase(), code: k.substring(0,1) };
    }
    seed.properties = p;

    return Object.freeze ? Object.freeze(seed) : seed;
}

此版本生成了一个允许友好名称转换和短代码的附加属性列表。我喜欢这个版本,因为不需要像代码那样在财产中重复数据输入。

var SizeEnum2 = mkenum_2({ SMALL: 1, MEDIUM: 2, LARGE: 3});
var SizeEnum3 = mkenum_2({ SMALL: [1, "small", "S"], MEDIUM: [2, "medium", "M"], LARGE: [3, "large", "L"] });

这两者可以组合成一个处理单元mkenum(使用enum、分配值、创建和添加属性列表)。然而,由于我今天已经在这方面花了太多时间,我将把这个组合作为练习留给亲爱的读者。

创建对象文字:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};

我不久前使用了__defineGetter__和__defineSetter__或defineProperty的组合,具体取决于JS版本。

下面是我制作的枚举生成函数:https://gist.github.com/gfarrell/6716853

你可以这样使用:

var Colours = Enum('RED', 'GREEN', 'BLUE');

它将创建一个不可变的字符串:int字典(一个枚举)。

最简单的解决方案:

创造

var Status = Object.freeze({
    "Connecting":0,
    "Ready":1,
    "Loading":2,
    "Processing": 3
});

获取价值

console.log(Status.Ready) // 1

获取密钥

console.log(Object.keys(Status)[Status.Ready]) // Ready