代码之家  ›  专栏  ›  技术社区  ›  David Citron

在JavaScript中定义枚举的首选语法是什么?

  •  1828
  • David Citron  · 技术社区  · 16 年前

    my.namespace.ColorEnum = {
        RED : 0,
        GREEN : 1,
        BLUE : 2
    }
    
    // later on
    
    if(currentColor == my.namespace.ColorEnum.RED) {
       // whatever
    }
    

    或者我还有别的办法吗?

    44 回复  |  直到 3 年前
        1
  •  1142
  •   LegionMammal978 Artur Czajka    4 年前

    从1.8.5开始,可以 seal and freeze the object ,因此将上述定义为:

    const DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})
    

    const DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}
    Object.freeze(DaysEnum)
    

    瞧!JS枚举。

    但是,这并不妨碍您为变量指定不需要的值,这通常是枚举的主要目标:

    let day = DaysEnum.tuesday
    day = 298832342 // goes through without any errors
    

    确保更高程度的类型安全性(使用枚举或其他方式)的一种方法是使用类似 TypeScript Flow

    不需要引用,但我保留了它们以保持一致性。

        2
  •  624
  •   Gareth    16 年前

    这不是一个很好的答案,但我个人认为这很好

    话虽如此,由于值是什么并不重要(您已经使用了0、1、2),因此如果您想要输出当前值,我将使用一个有意义的字符串。

        3
  •  519
  •   informatik01 Viswanath Lekshmanan    5 年前

    使现代化

    Enums in JavaScript .


    已可以对该名称发出警报:

    if (currentColor == my.namespace.ColorEnum.RED) {
       // alert name of currentColor (RED: 0)
       var col = my.namespace.ColorEnum;
       for (var name in col) {
         if (col[name] == col.RED)
           alert(name);
       }
    }
    

    或者,您可以将值设置为对象,这样您就可以吃蛋糕了:

    var SIZE = {
      SMALL : {value: 0, name: "Small", code: "S"}, 
      MEDIUM: {value: 1, name: "Medium", code: "M"}, 
      LARGE : {value: 2, name: "Large", code: "L"}
    };
    
    var currentSize = SIZE.MEDIUM;
    if (currentSize == SIZE.MEDIUM) {
      // this alerts: "1: Medium"
      alert(currentSize.value + ": " + currentSize.name);
    }
    

    在JavaScript中,由于它是一种动态语言,因此以后甚至可以向集合中添加枚举值:

    // Add EXTRALARGE size
    SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"};
    

    记住,枚举的字段(本例中的值、名称和代码)不需要用于身份检查,只是为了方便起见。此外,size属性本身的名称不需要硬编码,但也可以动态设置。因此,假设您只知道新枚举值的名称,您仍然可以添加它而不会出现问题:

    // Add 'Extra Large' size, only knowing it's name
    var name = "Extra Large";
    SIZE[name] = {value: -1, name: name, code: "?"};
    

    当然,这意味着无法再进行某些假设(例如,该值表示大小的正确顺序)。

    记住,在JavaScript中,对象就像 地图

    实例

    for (var sz in SIZE) {
      // sz will be the names of the objects in SIZE, so
      // 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'
      var size = SIZE[sz]; // Get the object mapped to the name in sz
      for (var prop in size) {
        // Get all the properties of the size object, iterates over
        // 'value', 'name' and 'code'. You can inspect everything this way.        
      }
    } 
    

    顺便说一句,如果您对名称空间感兴趣,您可能想看看我为JavaScript提供的简单但功能强大的名称空间和依赖关系管理解决方案: Packages JS

        4
  •  89
  •   Randolpho    12 年前

    var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}
    
    Document.Write("Enumerant: " + DaysEnum.tuesday);
    

    这种方法的问题是什么?您可能会意外地重新定义枚举数,或意外地具有重复的枚举数值。例如:

    DaysEnum.monday = 4; // whoops, monday is now thursday, too
    

    编辑

    那Artur Czajka的物体呢?别动?这难道不能阻止你把周一定到周四吗?油炸方

    绝对地 Object.freeze 会完全解决我抱怨的问题。我想提醒大家,当我写上述内容时, 对象。冻结 其实并不存在。

    现在现在它打开了一些 非常

    编辑2
    这里有一个非常好的创建枚举的库。

    http://www.2ality.com/2011/10/enums.html

    虽然它可能不适合枚举的所有有效使用,但它有很长的路要走。

        5
  •  61
  •   Andre 'Fi'    13 年前

    以下是我们都想要的:

    function Enum(constantsList) {
        for (var i in constantsList) {
            this[constantsList[i]] = i;
        }
    }
    

    var YesNo = new Enum(['NO', 'YES']);
    var Color = new Enum(['RED', 'GREEN', 'BLUE']);
    

    通过这样做,常数可以以通常的方式进行访问(YesNo.YES,Color.GREEN),它们得到一个连续的int值(NO=0,YES=1;RED=0,GREEN=1,BLUE=2)。

    还可以使用Enum.prototype添加方法:

    Enum.prototype.values = function() {
        return this.allValues;
        /* for the above to work, you'd need to do
                this.allValues = constantsList at the constructor */
    };
    


    function Enum() {
        for (var i in arguments) {
            this[arguments[i]] = i;
        }
    }
    
    var YesNo = new Enum('NO', 'YES');
    var Color = new Enum('RED', 'GREEN', 'BLUE');
    
        6
  •  58
  •   YakovL Naresh Kumar Nakka    7 年前

    在大多数现代浏览器中,都有一个 symbol 可用于创建枚举的基元数据类型。它将确保枚举的类型安全,因为JavaScript保证每个符号值都是唯一的,即。 Symbol() != Symbol() . 例如:

    const COLOR = Object.freeze({RED: Symbol(), BLUE: Symbol()});
    

    const COLOR = Object.freeze({RED: Symbol("RED"), BLUE: Symbol("BLUE")});
    

    Plunker demo

    GitHub 您可以找到简化初始化枚举所需代码的包装器:

    const color = new Enum("RED", "BLUE")
    
    color.RED.toString() // Symbol(RED)
    color.getName(color.RED) // RED
    color.size // 2
    color.values() // Symbol(RED), Symbol(BLUE)
    color.toString() // RED,BLUE
    
        7
  •  43
  •   Jack G    4 年前

    让我们直接切入问题:文件大小。这里列出的每一个答案都会将您的精简代码膨胀到极致。我向您介绍,为了通过在许多代码编辑器中进行缩小、性能、代码可读性、大规模项目管理和语法暗示来尽可能地减少代码大小,这是进行枚举的正确方法:下划线符号变量。


    Underscore-Notation Variables

    如上图和下面的示例所示,这里有五个简单的开始步骤:

    1. 确定枚举组的名称。想象一个可以描述枚举目的的名词,或者至少描述枚举中的条目。例如,表示用户可选择的颜色的一组枚举可能比颜色更适合命名为COLORCHOICES。
    2. 决定组中的枚举是互斥的还是独立的。如果互斥,则以 ENUM_ . 如果独立或并排,则使用 INDEX_
    3. 索引_ ,然后是组的名称,然后是下划线,然后是属性的唯一友好名称
    4. 添加 ENUMLENGTH_ ENUMLEN_ INDEXLENGTH_ INDEXLEN_ LEN_ LENGTH_ 是个人偏好)最后列举的变量。您应该尽可能在代码中使用此变量,以确保向枚举中添加额外条目并递增此值不会破坏代码。
    5. 0 不应用作枚举值,因为 0 == null , 0 == false 0 == "" ,以及其他疯狂行为。为了避免这个问题,同时提高性能,请始终使用 === 决不让 == 出现在您的代码中,除了 typeof (e.x。 typeof X == "string" === 1 可以用作中的起始值 枚举_ 索引_ 枚举)在许多情况下没有性能损失。
    const ENUM_COLORENUM_RED   = 0;
    const ENUM_COLORENUM_GREEN = 1;
    const ENUM_COLORENUM_BLUE  = 2;
    const ENUMLEN_COLORENUM    = 3;
    
    // later on
    
    if(currentColor === ENUM_COLORENUM_RED) {
       // whatever
    }
    

    索引_ :

    // Precondition: var arr = []; //
    arr[INDEX_] = ENUM_;
    

    然而 在某些情况下,可以用作索引,例如在计算每个项目的出现次数时。

    const ENUM_PET_CAT = 0,
          ENUM_PET_DOG = 1,
          ENUM_PET_RAT = 2,
          ENUMLEN_PET  = 3;
    
    var favoritePets = [ENUM_PET_CAT, ENUM_PET_DOG, ENUM_PET_RAT,
                        ENUM_PET_DOG, ENUM_PET_DOG, ENUM_PET_CAT,
                        ENUM_PET_RAT, ENUM_PET_CAT, ENUM_PET_DOG];
    
    var petsFrequency = [];
    
    for (var i=0; i<ENUMLEN_PET; i=i+1|0)
      petsFrequency[i] = 0;
    
    for (var i=0, len=favoritePets.length|0, petId=0; i<len; i=i+1|0)
      petsFrequency[petId = favoritePets[i]|0] = (petsFrequency[petId]|0) + 1|0;
    
    console.log({
        "cat": petsFrequency[ENUM_PET_CAT],
        "dog": petsFrequency[ENUM_PET_DOG],
        "rat": petsFrequency[ENUM_PET_RAT]
    });

    注意,在上面的代码中,添加一种新的宠物非常容易:只需在之后添加一个新条目 ENUM_PET_RAT ENUMLEN_PET 照着在其他枚举系统中添加一个新条目可能更困难,也更麻烦。


    此外,这种枚举语法允许进行清晰简洁的类扩展,如下所示。要扩展类,请向 父类的条目。然后,用自己的子类完成子类 这样子类将来可以进一步扩展。

    Addition extension diagram

    (function(window){
        "use strict";
        var parseInt = window.parseInt;
    
        // use INDEX_ when representing the index in an array instance
        const INDEX_PIXELCOLOR_TYPE = 0, // is a ENUM_PIXELTYPE
              INDEXLEN_PIXELCOLOR   = 1,
              INDEX_SOLIDCOLOR_R    = INDEXLEN_PIXELCOLOR+0,
              INDEX_SOLIDCOLOR_G    = INDEXLEN_PIXELCOLOR+1,
              INDEX_SOLIDCOLOR_B    = INDEXLEN_PIXELCOLOR+2,
              INDEXLEN_SOLIDCOLOR   = INDEXLEN_PIXELCOLOR+3,
              INDEX_ALPHACOLOR_R    = INDEXLEN_PIXELCOLOR+0,
              INDEX_ALPHACOLOR_G    = INDEXLEN_PIXELCOLOR+1,
              INDEX_ALPHACOLOR_B    = INDEXLEN_PIXELCOLOR+2,
              INDEX_ALPHACOLOR_A    = INDEXLEN_PIXELCOLOR+3,
              INDEXLEN_ALPHACOLOR   = INDEXLEN_PIXELCOLOR+4,
        // use ENUM_ when representing a mutually-exclusive species or type
              ENUM_PIXELTYPE_SOLID = 0,
              ENUM_PIXELTYPE_ALPHA = 1,
              ENUM_PIXELTYPE_UNKNOWN = 2,
              ENUMLEN_PIXELTYPE    = 2;
    
        function parseHexColor(inputString) {
            var rawstr = inputString.trim().substring(1);
            var result = [];
            if (rawstr.length === 8) {
                result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA;
                result[INDEX_ALPHACOLOR_R] = parseInt(rawstr.substring(0,2), 16);
                result[INDEX_ALPHACOLOR_G] = parseInt(rawstr.substring(2,4), 16);
                result[INDEX_ALPHACOLOR_B] = parseInt(rawstr.substring(4,6), 16);
                result[INDEX_ALPHACOLOR_A] = parseInt(rawstr.substring(4,6), 16);
            } else if (rawstr.length === 4) {
                result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA;
                result[INDEX_ALPHACOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
                result[INDEX_ALPHACOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
                result[INDEX_ALPHACOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
                result[INDEX_ALPHACOLOR_A] = parseInt(rawstr[3], 16) * 0x11;
            } else if (rawstr.length === 6) {
                result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
                result[INDEX_SOLIDCOLOR_R] = parseInt(rawstr.substring(0,2), 16);
                result[INDEX_SOLIDCOLOR_G] = parseInt(rawstr.substring(2,4), 16);
                result[INDEX_SOLIDCOLOR_B] = parseInt(rawstr.substring(4,6), 16);
            } else if (rawstr.length === 3) {
                result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
                result[INDEX_SOLIDCOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
                result[INDEX_SOLIDCOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
                result[INDEX_SOLIDCOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
            } else {
                result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_UNKNOWN;
            }
            return result;
        }
    
        // the red component of green
        console.log(parseHexColor("#0f0")[INDEX_SOLIDCOLOR_R]);
        // the alpha of transparent purple
        console.log(parseHexColor("#f0f7")[INDEX_ALPHACOLOR_A]); 
        // the enumerated array for turquoise
        console.log(parseHexColor("#40E0D0"));
    })(self);

    (长度:2450字节)

    有人可能会说,这比其他解决方案更不实用:它浪费了大量的空间,需要很长时间来编写,而且没有糖衣语法。如果这些人不缩小他们的代码,他们是对的。然而,任何通情达理的人都不会在最终产品中留下未统一的代码。对于这种缩小,闭包编译器是我迄今为止找到的最好的。可以找到在线访问 here . 闭包编译器能够获取所有这些枚举数据并将其内联,从而使您的Javascript非常小,运行起来非常快。因此,可以使用闭包编译器进行缩小。看到


    𝗖𝗹𝗼𝘀𝘂𝗿𝗲 𝗖𝗼𝗺𝗽𝗶𝗹𝗲𝗿

    闭包编译器能够通过推理执行一些非常难以置信的优化,这些推理远远超出了任何其他Javascript迷你程序的能力。闭包编译器能够将原始变量内联设置为固定值。闭包编译器还能够基于这些内联值进行推断,并消除if语句和循环中未使用的块。

    Wringing code via Closure Compiler

    'use strict';(function(e){function d(a){a=a.trim().substring(1);var b=[];8===a.length?(b[0]=1,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16),b[4]=c(a.substring(4,6),16)):4===a.length?(b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16),b[4]=17*c(a[3],16)):6===a.length?(b[0]=0,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16)):3===a.length?(b[0]=0,b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16)):b[0]=2;return b}var c=
    e.parseInt;console.log(d("#0f0")[1]);console.log(d("#f0f7")[4]);console.log(d("#40E0D0"))})(self);

    (长度:605字节)

    闭包编译器会奖励您更聪明地编写代码并很好地组织代码,因为许多缩略器会用更大的缩略文件大小来惩罚有组织的代码,而如果您使用变量名枚举之类的技巧,闭包编译器能够筛选您所有的整洁度和健全度,以输出更小的文件大小。在这一点上,这就是编码的圣杯:一种既能以较小的尺寸帮助您编写代码,又能通过培养更好的编程习惯来帮助您的思维的工具。




    Source Without Using Enumerations (长度:1973字节(比枚举代码短477字节!))
    Minified Without Using Enumerations 比枚举代码长 ))

    Chart of code sizes



    如图所示,在没有枚举的情况下,源代码更短,但代价是代码更大。我不了解你;但我确信我不会将源代码合并到最终产品中。因此,这种枚举形式的优越性非常大,它可以缩小文件大小。


    这种枚举形式的另一个优点是,它可以轻松地管理大型项目,而不会牺牲较小的代码大小。当与许多其他人一起处理一个大型项目时,显式地标记和标记变量名以及创建代码的人可能是有益的,这样就可以快速确定代码的原始创建者,以便进行协作性错误修复。

    // JG = Jack Giffin
    const ENUM_JG_COLORENUM_RED   = 0,
          ENUM_JG_COLORENUM_GREEN = 1,
          ENUM_JG_COLORENUM_BLUE  = 2,
          ENUMLEN_JG_COLORENUM    = 3;
    
    // later on
    
    if(currentColor === ENUM_JG_COLORENUM_RED) {
       // whatever
    }
    
    // PL = Pepper Loftus
    // BK = Bob Knight
    const ENUM_PL_ARRAYTYPE_UNSORTED   = 0,
          ENUM_PL_ARRAYTYPE_ISSORTED   = 1,
          ENUM_BK_ARRAYTYPE_CHUNKED    = 2, // added by Bob Knight
          ENUM_JG_ARRAYTYPE_INCOMPLETE = 3, // added by jack giffin
          ENUMLEN_PL_COLORENUM         = 4;
    
    // later on
    
    if(
      randomArray === ENUM_PL_ARRAYTYPE_UNSORTED ||
      randomArray === ENUM_BK_ARRAYTYPE_CHUNKED
    ) {
       // whatever
    }
    

    此外,这种形式的枚举在缩小后也要快得多。在普通命名属性中,浏览器必须使用hashmaps查找对象上的属性位置。尽管JIT编译器可以智能地在对象上缓存该位置,但由于特殊情况(如从对象中删除较低的属性),仍然会产生巨大的开销。

    但是,对于连续非稀疏整数索引 PACKED_ELEMENTS 数组,浏览器可以跳过大部分开销,因为内部数组中的值的索引已经指定。是的,根据ECMAScript标准,所有属性都应该被视为字符串。然而,ECMAScript标准的这一方面在性能方面是非常误导的,因为所有浏览器都对数组中的数字索引进行了特殊的优化。

    /// Hashmaps are slow, even with JIT juice
    var ref = {};
    ref.count = 10;
    ref.value = "foobar";
    

    将上面的代码与下面的代码进行比较。

    /// Arrays, however, are always lightning fast
    const INDEX_REFERENCE_COUNT = 0;
    const INDEX_REFERENCE_VALUE = 1;
    const INDEXLENGTH_REFERENCE = 2;
    
    var ref = [];
    ref[INDEX_REFERENCE_COUNT] = 10;
    ref[INDEX_REFERENCE_VALUE] = "foobar";
    

    有人可能会反对使用枚举的代码看起来比使用普通对象的代码要长得多,但外观可能是欺骗。使用epic闭包编译器时,请务必记住源代码大小与输出大小不成正比。看到

    /// Hashmaps are slow, even with JIT juice
    var a={count:10,value:"foobar"};
    

    上面是不带枚举的缩小代码,下面是带枚举的缩小代码。

    /// Arrays, however, are always lightning fast
    var a=[10,"foobar"];
    

    上面的示例表明,除了具有优异的性能外,枚举代码还可以缩小文件大小。


    𝗘𝗮𝘀𝘆 𝗗𝗲𝗯𝘂𝗴𝗴𝗶𝗻𝗴

    上面的樱桃 正在将这种形式的枚举与 CodeMirror Javascript模式下的文本编辑器。CodeMirror的Javascript语法突出显示模式突出显示当前作用域中的局部变量。这样,您就可以立即知道何时正确键入变量名,因为如果变量名以前是用 var 关键字,则变量名将变为特殊颜色(默认为青色)。即使您不使用CodeMirror,那么至少浏览器会抛出一个有用的提示 [variable name] is not defined 执行枚举名称键入错误的代码时发生异常。此外,JSLint和Closure Compiler等JavaScript工具在错误键入枚举变量名时会大声告诉您。CodeMirror、浏览器和各种Javascript工具结合在一起,使得调试这种枚举形式非常简单和容易。

    CodeMirror highlighting demonstration

    const ENUM_COLORENUM_RED   = 0,
          ENUM_COLORENUM_GREEN = 1,
          ENUM_COLORENUM_BLUE  = 2,
          ENUMLEN_COLORENUM    = 3;
    var currentColor = ENUM_COLORENUM_GREEN;
    
    if(currentColor === ENUM_COLORENUM_RED) {
       // whatever
    }
    
    if(currentColor === ENUM_COLORENUM_DNE) {
       // whatever
    }

    在上面的代码段中,您收到了一个错误警报,因为 ENUM_COLORENUM_DNE


    °

    我认为可以肯定地说,这种枚举方法确实是最好的方法,不仅适用于缩小代码大小,而且适用于性能、调试和协作。

        8
  •  30
  •   j2k Govind Rai    6 年前

    使用Javascript Proxies

    TLDR: 将该类添加到实用程序方法中并在整个代码中使用,它模仿传统编程语言中的枚举行为,并在尝试访问不存在的枚举数或添加/更新枚举数时实际抛出错误。无需依赖 Object.freeze()

    class Enum {
      constructor(enumObj) {
        const handler = {
          get(target, name) {
            if (typeof target[name] != 'undefined') {
              return target[name];
            }
            throw new Error(`No such enumerator: ${name}`);
          },
          set() {
            throw new Error('Cannot add/update properties on an Enum instance after it is defined')
          }
        };
    
        return new Proxy(enumObj, handler);
      }
    }
    

    const roles = new Enum({
      ADMIN: 'Admin',
      USER: 'User',
    });
    

    详细说明:

    从传统语言中获得的枚举的一个非常有益的特性是,如果您试图访问一个不存在的枚举数,它们就会爆炸(抛出编译时错误)。

    除了冻结模拟枚举结构以防止意外/恶意添加附加值之外,其他答案都没有解决枚举的固有特性。

    您可能知道,访问JavaScript中不存在的成员只会返回 undefined

    别误会,JavaScript的返回行为 当访问未定义的属性时,它实际上是语言的一个非常强大的功能,但当您试图模拟传统的枚举结构时,它并不是您想要的功能。

    这就是代理对象发光的地方。随着ES6(ES2015)的引入,代理被标准化为该语言。以下是MDN的描述:

    代理对象用于定义基本操作(例如属性查找、赋值、枚举、函数)的自定义行为 调用等)。

    与web服务器代理类似,JavaScript代理能够拦截对象上的操作(使用“陷阱”,如果您愿意,可以称它们为钩子),并允许您在对象完成之前执行各种检查、操作和/或操作(或者在某些情况下完全停止操作,这正是我们在尝试引用不存在的枚举数时想要做的事情)。

    // Class for creating enums (13 lines)
    // Feel free to add this to your utility library in 
    // your codebase and profit! Note: As Proxies are an ES6 
    // feature, some browsers/clients may not support it and 
    // you may need to transpile using a service like babel
    
    class Enum {
      // The Enum class instantiates a JavaScript Proxy object.
      // Instantiating a `Proxy` object requires two parameters, 
      // a `target` object and a `handler`. We first define the handler,
      // then use the handler to instantiate a Proxy.
    
      // A proxy handler is simply an object whose properties
      // are functions which define the behavior of the proxy 
      // when an operation is performed on it. 
      
      // For enums, we need to define behavior that lets us check what enumerator
      // is being accessed and what enumerator is being set. This can be done by 
      // defining "get" and "set" traps.
      constructor(enumObj) {
        const handler = {
          get(target, name) {
            if (typeof target[name] != 'undefined') {
              return target[name]
            }
            throw new Error(`No such enumerator: ${name}`)
          },
          set() {
            throw new Error('Cannot add/update properties on an Enum instance after it is defined')
          }
        }
    
    
        // Freeze the target object to prevent modifications
        return new Proxy(enumObj, handler)
      }
    }
    
    
    // Now that we have a generic way of creating Enums, lets create our first Enum!
    const httpMethods = new Enum({
      DELETE: "DELETE",
      GET: "GET",
      OPTIONS: "OPTIONS",
      PATCH: "PATCH",
      POST: "POST",
      PUT: "PUT"
    })
    
    // Sanity checks
    console.log(httpMethods.DELETE)
    // logs "DELETE"
    
    try {
      httpMethods.delete = "delete"
    } catch (e) {
    console.log("Error: ", e.message)
    }
    // throws "Cannot add/update properties on an Enum instance after it is defined"
    
    try {
      console.log(httpMethods.delete)
    } catch (e) {
      console.log("Error: ", e.message)
    }
    // throws "No such enumerator: delete"

    旁白:代理到底是什么?

        9
  •  23
  •   Duncan    11 年前

    我一直在玩这个,因为我喜欢我的枚举

    使用 Object.defineProperty 我想我找到了一个可行的解决办法。

    下面是一个JSFIDLE: http://jsfiddle.net/ZV4A6/

    Object.defineProperty(Object.prototype,'Enum', {
        value: function() {
            for(i in arguments) {
                Object.defineProperty(this,arguments[i], {
                    value:parseInt(i),
                    writable:false,
                    enumerable:true,
                    configurable:true
                });
            }
            return this;
        },
        writable:false,
        enumerable:false,
        configurable:false
    }); 
    

    因为这个属性 writable:false 确保它的类型安全。

    因此,您应该能够创建一个自定义对象,然后调用 Enum() 在上面。分配的值从0开始,每项递增。

    var EnumColors={};
    EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
    EnumColors.RED;    // == 0
    EnumColors.BLUE;   // == 1
    EnumColors.GREEN;  // == 2
    EnumColors.YELLOW; // == 3
    
        10
  •  17
  •   Rob Hardy    11 年前

    我知道这是一个旧版本,但后来通过TypeScript接口实现它的方式是:

    var MyEnum;
    (function (MyEnum) {
        MyEnum[MyEnum["Foo"] = 0] = "Foo";
        MyEnum[MyEnum["FooBar"] = 2] = "FooBar";
        MyEnum[MyEnum["Bar"] = 1] = "Bar";
    })(MyEnum|| (MyEnum= {}));
    

    MyEnum.Bar MyEnum[1] 无论声明的顺序如何,它都返回“Bar”。

        11
  •  17
  •   Abdennour TOUMI    8 年前

    在里面 ES7 ,您可以根据静态属性执行优雅的枚举:

    class ColorEnum  {
        static RED = 0 ;
        static GREEN = 1;
        static BLUE = 2;
    }
    

    然后

    if (currentColor === ColorEnum.GREEN ) {/*-- coding --*/}
    

    Enum 那么你所有的枚举都会 延伸 那个班。

     class ColorEnum  extends Enum {/*....*/}
    
        12
  •  15
  •   Chris    13 年前

    这就是我使用的解决方案。

    function Enum() {
        this._enums = [];
        this._lookups = {};
    }
    
    Enum.prototype.getEnums = function() {
        return _enums;
    }
    
    Enum.prototype.forEach = function(callback){
        var length = this._enums.length;
        for (var i = 0; i < length; ++i){
            callback(this._enums[i]);
        }
    }
    
    Enum.prototype.addEnum = function(e) {
        this._enums.push(e);
    }
    
    Enum.prototype.getByName = function(name) {
        return this[name];
    }
    
    Enum.prototype.getByValue = function(field, value) {
        var lookup = this._lookups[field];
        if(lookup) {
            return lookup[value];
        } else {
            this._lookups[field] = ( lookup = {});
            var k = this._enums.length - 1;
            for(; k >= 0; --k) {
                var m = this._enums[k];
                var j = m[field];
                lookup[j] = m;
                if(j == value) {
                    return m;
                }
            }
        }
        return null;
    }
    
    function defineEnum(definition) {
        var k;
        var e = new Enum();
        for(k in definition) {
            var j = definition[k];
            e[k] = j;
            e.addEnum(j)
        }
        return e;
    }
    

    您可以这样定义枚举:

    var COLORS = defineEnum({
        RED : {
            value : 1,
            string : 'red'
        },
        GREEN : {
            value : 2,
            string : 'green'
        },
        BLUE : {
            value : 3,
            string : 'blue'
        }
    });
    

    以下是访问枚举的方式:

    COLORS.BLUE.string
    COLORS.BLUE.value
    COLORS.getByName('BLUE').string
    COLORS.getByValue('value', 1).string
    
    COLORS.forEach(function(e){
        // do what you want with e
    });
    

    我通常使用最后两种方法从消息对象映射枚举。

    这种方法的一些优点:

    • 易于访问您的枚举
    • 枚举可以是复杂类型
    • 如果经常使用getByValue,则Enum类具有一些关联缓存

    一些缺点:

    • 一些混乱的内存管理正在那里进行,因为我保留了对枚举的引用
        13
  •  15
  •   hvdd    7 年前

    创建对象文字:

    const Modes = {
      DRAGGING: 'drag',
      SCALING:  'scale',
      CLICKED:  'click'
    };
    
        14
  •  11
  •   Yaroslav    13 年前

    如果你正在使用 Backbone Backbone.Collection .

    // enum instance members, optional
    var Color = Backbone.Model.extend({
        print : function() {
            console.log("I am " + this.get("name"))
        }
    });
    
    // enum creation
    var Colors = new Backbone.Collection([
        { id : 1, name : "Red", rgb : 0xFF0000},
        { id : 2, name : "Green" , rgb : 0x00FF00},
        { id : 3, name : "Blue" , rgb : 0x0000FF}
    ], {
        model : Color
    });
    
    // Expose members through public fields.
    Colors.each(function(color) {
        Colors[color.get("name")] = color;
    });
    
    // using
    Colors.Red.print()
    
        15
  •  8
  •   Xeltor    11 年前

    你的答案太复杂了

    var buildSet = function(array) {
      var set = {};
      for (var i in array) {
        var item = array[i];
        set[item] = item;
      }
      return set;
    }
    
    var myEnum = buildSet(['RED','GREEN','BLUE']);
    // myEnum.RED == 'RED' ...etc
    
        16
  •  7
  •   David Miró    12 年前

      function Enum() {
        var that = this;
        for (var i in arguments) {
            that[arguments[i]] = i;
        }
        this.name = function(value) {
            for (var key in that) {
                if (that[key] == value) {
                    return key;
                }
            }
        };
        this.exist = function(value) {
            return (typeof that.name(value) !== "undefined");
        };
        if (Object.freeze) {
            Object.freeze(that);
        }
      }
    

    测试:

    var Color = new Enum('RED', 'GREEN', 'BLUE');
    undefined
    Color.name(Color.REDs)
    undefined
    Color.name(Color.RED)
    "RED"
    Color.exist(Color.REDs)
    false
    Color.exist(Color.RED)
    true
    
        17
  •  7
  •   Vivin Paliath    9 年前

    我想出了 this instanceof 还有支票。

    您可以这样定义枚举:

    var Days = Enum.define("Days", ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]);
    

    Days 枚举:

    Days.Monday instanceof Days; // true
    
    Days.Friday.name(); // "Friday"
    Days.Friday.ordinal(); // 4
    
    Days.Sunday === Days.Sunday; // true
    Days.Sunday === Days.Friday; // false
    
    Days.Sunday.toString(); // "Sunday"
    
    Days.toString() // "Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } "
    
    Days.values().map(function(e) { return e.name(); }); //["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
    Days.values()[4].name(); //"Friday"
    
    Days.fromName("Thursday") === Days.Thursday // true
    Days.fromName("Wednesday").name() // "Wednesday"
    Days.Friday.fromName("Saturday").name() // "Saturday"
    

    var Enum = (function () {
        /**
         * Function to define an enum
         * @param typeName - The name of the enum.
         * @param constants - The constants on the enum. Can be an array of strings, or an object where each key is an enum
         * constant, and the values are objects that describe attributes that can be attached to the associated constant.
         */
        function define(typeName, constants) {
    
            /** Check Arguments **/
            if (typeof typeName === "undefined") {
                throw new TypeError("A name is required.");
            }
    
            if (!(constants instanceof Array) && (Object.getPrototypeOf(constants) !== Object.prototype)) {
    
                throw new TypeError("The constants parameter must either be an array or an object.");
    
            } else if ((constants instanceof Array) && constants.length === 0) {
    
                throw new TypeError("Need to provide at least one constant.");
    
            } else if ((constants instanceof Array) && !constants.reduce(function (isString, element) {
                    return isString && (typeof element === "string");
                }, true)) {
    
                throw new TypeError("One or more elements in the constant array is not a string.");
    
            } else if (Object.getPrototypeOf(constants) === Object.prototype && !Object.keys(constants).reduce(function (isObject, constant) {
                    return Object.getPrototypeOf(constants[constant]) === Object.prototype;
                }, true)) {
    
                throw new TypeError("One or more constants do not have an associated object-value.");
    
            }
    
            var isArray = (constants instanceof Array);
            var isObject = !isArray;
    
            /** Private sentinel-object used to guard enum constructor so that no one else can create enum instances **/
            function __() { };
    
            /** Dynamically define a function with the same name as the enum we want to define. **/
            var __enum = new Function(["__"],
                "return function " + typeName + "(sentinel, name, ordinal) {" +
                    "if(!(sentinel instanceof __)) {" +
                        "throw new TypeError(\"Cannot instantiate an instance of " + typeName + ".\");" +
                    "}" +
    
                    "this.__name = name;" +
                    "this.__ordinal = ordinal;" +
                "}"
            )(__);
    
            /** Private objects used to maintain enum instances for values(), and to look up enum instances for fromName() **/
            var __values = [];
            var __dict = {};
    
            /** Attach values() and fromName() methods to the class itself (kind of like static methods). **/
            Object.defineProperty(__enum, "values", {
                value: function () {
                    return __values;
                }
            });
    
            Object.defineProperty(__enum, "fromName", {
                value: function (name) {
                    var __constant = __dict[name]
                    if (__constant) {
                        return __constant;
                    } else {
                        throw new TypeError(typeName + " does not have a constant with name " + name + ".");
                    }
                }
            });
    
            /**
             * The following methods are available to all instances of the enum. values() and fromName() need to be
             * available to each constant, and so we will attach them on the prototype. But really, they're just
             * aliases to their counterparts on the prototype.
             */
            Object.defineProperty(__enum.prototype, "values", {
                value: __enum.values
            });
    
            Object.defineProperty(__enum.prototype, "fromName", {
                value: __enum.fromName
            });
    
            Object.defineProperty(__enum.prototype, "name", {
                value: function () {
                    return this.__name;
                }
            });
    
            Object.defineProperty(__enum.prototype, "ordinal", {
                value: function () {
                    return this.__ordinal;
                }
            });
    
            Object.defineProperty(__enum.prototype, "valueOf", {
                value: function () {
                    return this.__name;
                }
            });
    
            Object.defineProperty(__enum.prototype, "toString", {
                value: function () {
                    return this.__name;
                }
            });
    
            /**
             * If constants was an array, we can the element values directly. Otherwise, we will have to use the keys
             * from the constants object.
             */
            var _constants = constants;
            if (isObject) {
                _constants = Object.keys(constants);
            }
    
            /** Iterate over all constants, create an instance of our enum for each one, and attach it to the enum type **/
            _constants.forEach(function (name, ordinal) {
                // Create an instance of the enum
                var __constant = new __enum(new __(), name, ordinal);
    
                // If constants was an object, we want to attach the provided attributes to the instance.
                if (isObject) {
                    Object.keys(constants[name]).forEach(function (attr) {
                        Object.defineProperty(__constant, attr, {
                            value: constants[name][attr]
                        });
                    });
                }
    
                // Freeze the instance so that it cannot be modified.
                Object.freeze(__constant);
    
                // Attach the instance using the provided name to the enum type itself.
                Object.defineProperty(__enum, name, {
                    value: __constant
                });
    
                // Update our private objects
                __values.push(__constant);
                __dict[name] = __constant;
            });
    
            /** Define a friendly toString method for the enum **/
            var string = typeName + " { " + __enum.values().map(function (c) {
                    return c.name();
                }).join(", ") + " } ";
    
            Object.defineProperty(__enum, "toString", {
                value: function () {
                    return string;
                }
            });
    
            /** Freeze our private objects **/
            Object.freeze(__values);
            Object.freeze(__dict);
    
            /** Freeze the prototype on the enum and the enum itself **/
            Object.freeze(__enum.prototype);
            Object.freeze(__enum);
    
            /** Return the enum **/
            return __enum;
        }
    
        return {
            define: define
        }
    
    })();
    
        18
  •  7
  •   Andrew    5 年前

    我对任何一个答案都不满意,所以我做出了决定 .

    这一实施:

    • 使用更多最新的JS
    • 按名称进行映射( colors.RED colors["RED"] colors[0] ),但您只需要将字符串作为数组传入
    • 绑定等价物 toString() valueOf() 每个enum对象的函数(如果不希望这样做,可以简单地将其删除—不过JS的开销很小)
    • 具有可选的全局命名/按名称字符串存储
    • 创建后冻结枚举对象,使其无法修改

    Andre 'Fi''s answer 为了一些灵感。


    class Enums {
      static create({ name = undefined, items = [] }) {
        let newEnum = {};
        newEnum.length = items.length;
        newEnum.items = items;
        for (let itemIndex in items) {
          //Map by name.
          newEnum[items[itemIndex]] = parseInt(itemIndex, 10);
          //Map by index.
          newEnum[parseInt(itemIndex, 10)] = items[itemIndex];
        }
        newEnum.toString = Enums.enumToString.bind(newEnum);
        newEnum.valueOf = newEnum.toString;
        //Optional naming and global registration.
        if (name != undefined) {
          newEnum.name = name;
          Enums[name] = newEnum;
        }
        //Prevent modification of the enum object.
        Object.freeze(newEnum);
        return newEnum;
      }
      static enumToString() {
        return "Enum " +
          (this.name != undefined ? this.name + " " : "") +
          "[" + this.items.toString() + "]";
      }
    }
    

    用法:

    let colors = Enums.create({
      name: "COLORS",
      items: [ "RED", "GREEN", "BLUE", "PORPLE" ]
    });
    
    //Global access, if named.
    Enums.COLORS;
    
    colors.items; //Array(4) [ "RED", "GREEN", "BLUE", "PORPLE" ]
    colors.length; //4
    
    colors.RED; //0
    colors.GREEN; //1
    colors.BLUE; //2
    colors.PORPLE; //3
    colors[0]; //"RED"
    colors[1]; //"GREEN"
    colors[2]; //"BLUE"
    colors[3]; //"PORPLE"
    
    colors.toString(); //"Enum COLORS [RED,GREEN,BLUE,PORPLE]"
    
    //Enum frozen, makes it a real enum.
    colors.RED = 9001;
    colors.RED; //0
    
        19
  •  6
  •   Manohar Reddy Poreddy    8 年前


    资料来源: http://kangax.github.io/compat-table/es5/

    在我当前的游戏项目中,我使用了以下方法,因为很少有客户仍然使用IE8:

    var CONST_WILD_TYPES = {
        REGULAR: 'REGULAR',
        EXPANDING: 'EXPANDING',
        STICKY: 'STICKY',
        SHIFTING: 'SHIFTING'
    };
    

    我们还可以做:

    var CONST_WILD_TYPES = {
        REGULAR: 'RE',
        EXPANDING: 'EX',
        STICKY: 'ST',
        SHIFTING: 'SH'
    };
    

    甚至这个:

    var CONST_WILD_TYPES = {
        REGULAR: '1',
        EXPANDING: '2',
        STICKY: '3',
        SHIFTING: '4'
    };
    


    当然,现在您有责任确保数据中没有冲突(RE、EX等必须是唯一的,1、2等也应该是唯一的)。请注意,为了向后兼容,您需要永久维护这些。

    任务:

    var wildType = CONST_WILD_TYPES.REGULAR;
    

    比较:

    if (wildType === CONST_WILD_TYPES.REGULAR) {
        // do something here
    }
    
        20
  •  5
  •   Shivanshu Goyal    10 年前
    var ColorEnum = {
        red: {},
        green: {},
        blue: {}
    }
    

        21
  •  5
  •   Ilya Gazman    8 年前

    最简单的解决方案:

    创造

    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
    
        22
  •  5
  •   Joseph Merdrignac    7 年前

    const ThreeWiseMen = new Enum('Melchior', 'Caspar', 'Balthazar')
    
    for (let name of ThreeWiseMen)
        console.log(name)
    
    
    // with a given key
    let key = ThreeWiseMen.Melchior
    
    console.log(key in ThreeWiseMen) // true (string conversion, also true: 'Melchior' in ThreeWiseMen)
    
    for (let entry from key.enum)
         console.log(entry)
    
    
    // prevent alteration (throws TypeError in strict mode)
    ThreeWiseMen.Me = 'Me too!'
    ThreeWiseMen.Melchior.name = 'Foo'
    

    代码:

    class EnumKey {
    
        constructor(props) { Object.freeze(Object.assign(this, props)) }
    
        toString() { return this.name }
    
    }
    
    export class Enum {
    
        constructor(...keys) {
    
            for (let [index, key] of keys.entries()) {
    
                Object.defineProperty(this, key, {
    
                    value: new EnumKey({ name:key, index, enum:this }),
                    enumerable: true,
    
                })
    
            }
    
            Object.freeze(this)
    
        }
    
        *[Symbol.iterator]() {
    
            for (let key of Object.keys(this))
                yield this[key]
    
        }
    
        toString() { return [...this].join(', ') }
    
    }
    
        23
  •  5
  •   Carl Smith kyle k    4 年前

    这可能很有用:

    const [CATS, DOGS, BIRDS] = ENUM();
    

    实施过程简单高效:

    function * ENUM(count=1) { while(true) yield count++ }
    

    1

        24
  •  4
  •   user2254487    11 年前

    一个快速而简单的方法是:

    var Colors = function(){
    return {
        'WHITE':0,
        'BLACK':1,
        'RED':2,
        'GREEN':3
        }
    }();
    
    console.log(Colors.WHITE)  //this prints out "0"
    
        25
  •  4
  •   Blake Bowen    10 年前

    TypeScript enums .

    最简单的方法是在对象上迭代,向对象添加反转的键值对。唯一的缺点是必须手动设置每个成员的值。

    function _enum(list) {       
      for (var key in list) {
        list[list[key] = list[key]] = key;
      }
      return Object.freeze(list);
    }
    
    var Color = _enum({
      Red: 0,
      Green: 5,
      Blue: 2
    });
    
    // Color → {0: "Red", 2: "Blue", 5: "Green", "Red": 0, "Green": 5, "Blue": 2}
    // Color.Red → 0
    // Color.Green → 5
    // Color.Blue → 2
    // Color[5] → Green
    // Color.Blue > Color.Green → false
    


    这里有一个 lodash mixin

    function enum() {
        var key, val = -1, list = {};
        _.reduce(_.toArray(arguments), function(result, kvp) {    
            kvp = kvp.split("=");
            key = _.trim(kvp[0]);
            val = _.parseInt(kvp[1]) || ++val;            
            result[result[val] = key] = val;
            return result;
        }, list);
        return Object.freeze(list);
    }    
    
    // Add enum to lodash 
    _.mixin({ "enum": enum });
    
    var Color = _.enum(
        "Red",
        "Green",
        "Blue = 5",
        "Yellow",
        "Purple = 20",
        "Gray"
    );
    
    // Color.Red → 0
    // Color.Green → 1
    // Color.Blue → 5
    // Color.Yellow → 6
    // Color.Purple → 20
    // Color.Gray → 21
    // Color[5] → Blue
    
        26
  •  4
  •   Gelin Luo    10 年前

    我刚刚发布了一个NPM包 gen_enum 允许您在Javascript中快速创建枚举数据结构:

    var genEnum = require('gen_enum');
    
    var AppMode = genEnum('SIGN_UP, LOG_IN, FORGOT_PASSWORD');
    var curMode = AppMode.LOG_IN;
    console.log(curMode.isLogIn()); // output true 
    console.log(curMode.isSignUp()); // output false 
    console.log(curMode.isForgotPassword()); // output false 
    

    这个小工具的一个优点是在现代环境中(包括nodejs和ie9+浏览器),返回的Enum对象是不可变的。

    欲了解更多信息,请结帐 https://github.com/greenlaw110/enumjs

    我过时了 gen_enum 将函数打包并合并到 constjs https://www.npmjs.com/package/constjs 更多信息

    gen_enum constjs

    var genEnum = require('gen_enum');
    

    var genEnum = require('constjs').enum;
    
        27
  •  4
  •   Tim Kara Oooogi    8 年前

    我创建了一个枚举类,它可以在O(1)处获取值和名称。它还可以生成包含所有名称和值的对象数组。

    function Enum(obj) {
        // Names must be unique, Values do not.
        // Putting same values for different Names is risky for this implementation
    
        this._reserved = {
            _namesObj: {},
            _objArr: [],
            _namesArr: [],
            _valuesArr: [],
            _selectOptionsHTML: ""
        };
    
        for (k in obj) {
            if (obj.hasOwnProperty(k)) {
                this[k] = obj[k];
                this._reserved._namesObj[obj[k]] = k;
            }
        }
    }
    (function () {
        this.GetName = function (val) {
            if (typeof this._reserved._namesObj[val] === "undefined")
                return null;
            return this._reserved._namesObj[val];
        };
    
        this.GetValue = function (name) {
            if (typeof this[name] === "undefined")
                return null;
            return this[name];
        };
    
        this.GetObjArr = function () {
            if (this._reserved._objArr.length == 0) {
                var arr = [];
                for (k in this) {
                    if (this.hasOwnProperty(k))
                        if (k != "_reserved")
                            arr.push({
                                Name: k,
                                Value: this[k]
                            });
                }
                this._reserved._objArr = arr;
            }
            return this._reserved._objArr;
        };
    
        this.GetNamesArr = function () {
            if (this._reserved._namesArr.length == 0) {
                var arr = [];
                for (k in this) {
                    if (this.hasOwnProperty(k))
                        if (k != "_reserved")
                            arr.push(k);
                }
                this._reserved._namesArr = arr;
            }
            return this._reserved._namesArr;
        };
    
        this.GetValuesArr = function () {
            if (this._reserved._valuesArr.length == 0) {
                var arr = [];
                for (k in this) {
                    if (this.hasOwnProperty(k))
                        if (k != "_reserved")
                            arr.push(this[k]);
                }
                this._reserved._valuesArr = arr;
            }
            return this._reserved._valuesArr;
        };
    
        this.GetSelectOptionsHTML = function () {
            if (this._reserved._selectOptionsHTML.length == 0) {
                var html = "";
                for (k in this) {
                    if (this.hasOwnProperty(k))
                        if (k != "_reserved")
                            html += "<option value='" + this[k] + "'>" + k + "</option>";
                }
                this._reserved._selectOptionsHTML = html;
            }
            return this._reserved._selectOptionsHTML;
        };
    }).call(Enum.prototype);
    

    var enum1 = new Enum({
        item1: 0,
        item2: 1,
        item3: 2
    });
    

    var val2 = enum1.item2;
    

    要获取值的名称(在为不同的名称放置相同的值时可能不明确):

    var name1 = enum1.GetName(0);  // "item1"
    

    获取包含每个名称的数组&对象中的值:

    var arr = enum1.GetObjArr();
    

    [{ Name: "item1", Value: 0}, { ... }, ... ]
    

    var html = enum1.GetSelectOptionsHTML();
    

    其中包括:

    "<option value='0'>item1</option>..."
    
        28
  •  4
  •   Marcus Junius Brutus    8 年前

    尽管 only static methods (而非静态属性)在ES2015中受支持(请参见 here es2015 预设:

    class CellState {
        v: string;
        constructor(v: string) {
            this.v = v;
            Object.freeze(this);
        }
        static EMPTY       = new CellState('e');
        static OCCUPIED    = new CellState('o');
        static HIGHLIGHTED = new CellState('h');
        static values      = function(): Array<CellState> {
            const rv = [];
            rv.push(CellState.EMPTY);
            rv.push(CellState.OCCUPIED);
            rv.push(CellState.HIGHLIGHTED);
            return rv;
        }
    }
    Object.freeze(CellState);
    

    我发现即使跨模块(例如导入 CellState

    与大多数其他答案相比,此方法的优势在于,您可以将其与静态类型检查器一起使用 (例如。 Flow 细胞状态

    使现代化

    细胞状态 (即使无法将它们指定给 因为它是冰冻的)。尽管如此,下面更精细的代码提供了以下优势:

    1. 细胞状态 可以创建
    2. 可以保证没有两个枚举实例被分配相同的代码
    3. 从字符串表示形式获取枚举的实用方法
    4. 这个 values 返回枚举的所有实例的函数不必以上述手动(且容易出错)方式创建返回值。

      'use strict';
      
      class Status {
      
      constructor(code, displayName = code) {
          if (Status.INSTANCES.has(code))
              throw new Error(`duplicate code value: [${code}]`);
          if (!Status.canCreateMoreInstances)
              throw new Error(`attempt to call constructor(${code}`+
             `, ${displayName}) after all static instances have been created`);
          this.code        = code;
          this.displayName = displayName;
          Object.freeze(this);
          Status.INSTANCES.set(this.code, this);
      }
      
      toString() {
          return `[code: ${this.code}, displayName: ${this.displayName}]`;
      }
      static INSTANCES   = new Map();
      static canCreateMoreInstances      = true;
      
      // the values:
      static ARCHIVED    = new Status('Archived');
      static OBSERVED    = new Status('Observed');
      static SCHEDULED   = new Status('Scheduled');
      static UNOBSERVED  = new Status('Unobserved');
      static UNTRIGGERED = new Status('Untriggered');
      
      static values      = function() {
          return Array.from(Status.INSTANCES.values());
      }
      
      static fromCode(code) {
          if (!Status.INSTANCES.has(code))
              throw new Error(`unknown code: ${code}`);
          else
              return Status.INSTANCES.get(code);
      }
      }
      
      Status.canCreateMoreInstances = false;
      Object.freeze(Status);
      exports.Status = Status;
      
        29
  •  4
  •   Julius Dzidzevičius    7 年前

    这就是Typescript如何翻译它的 enum

    var makeEnum = function(obj) {
        obj[ obj['Active'] = 1 ] = 'Active';
        obj[ obj['Closed'] = 2 ] = 'Closed';
        obj[ obj['Deleted'] = 3 ] = 'Deleted';
    }
    

    现在:

    makeEnum( NewObj = {} )
    // => {1: "Active", 2: "Closed", 3: "Deleted", Active: 1, Closed: 2, Deleted: 3}
    

    起初我不明白为什么 obj[1] 'Active' 赋值运算符 指定值,然后返回该值:

    obj['foo'] = 1
    // => 1
    
        30
  •  4
  •   LNT    6 年前

    你可以这样做

        var Enum = (function(foo) {
    
        var EnumItem = function(item){
            if(typeof item == "string"){
                this.name = item;
            } else {
                this.name = item.name;
            }
        }
        EnumItem.prototype = new String("DEFAULT");
        EnumItem.prototype.toString = function(){
            return this.name;
        }
        EnumItem.prototype.equals = function(item){
            if(typeof item == "string"){
                return this.name == item;
            } else {
                return this == item && this.name == item.name;
            }
        }
    
        function Enum() {
            this.add.apply(this, arguments);
            Object.freeze(this);
        }
        Enum.prototype.add = function() {
            for (var i in arguments) {
                var enumItem = new EnumItem(arguments[i]);
                this[enumItem.name] = enumItem;
            }
        };
        Enum.prototype.toList = function() {
            return Object.keys(this);
        };
        foo.Enum = Enum;
        return Enum;
    })(this);
    var STATUS = new Enum("CLOSED","PENDING", { name : "CONFIRMED", ackd : true });
    var STATE = new Enum("CLOSED","PENDING","CONFIRMED",{ name : "STARTED"},{ name : "PROCESSING"});
    

    如本库中所定义。 https://github.com/webmodule/foo/blob/master/foo.js#L217

    https://gist.github.com/lnt/bb13a2fd63cdb8bce85fd62965a20026