Jaka jest preferowana składnia definiowania enum w JavaScript?

Jaka jest preferowana składnia definiowania enum w JavaScript? Coś w stylu:

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

// later on

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

Czy Jest jakiś bardziej pożądany idiom?

Author: Flip, 2008-11-13

30 answers

Od wersji 1.8.5 możliwe jest zapieczętowanie i zamrożenie obiektu, więc zdefiniuj powyższe jako:

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

Lub

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}
Object.freeze(DaysEnum)
I voila! Js enums.

Jednak nie uniemożliwia to przypisania niepożądanej wartości zmiennej, co często jest głównym celem enum:

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

Jednym ze sposobów zapewnienia większego bezpieczeństwa typu (z enumami lub w inny sposób) jest użycie narzędzia typu TypeScript lub Flow .

Źródło

Cytaty nie są potrzebne, ale zatrzymałem je dla spójności.

 583
Author: Artur Czajka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-25 00:04:55

To nie jest zbyt duża odpowiedź, ale powiedziałbym, że działa dobrze, osobiście

Powiedziawszy to, ponieważ nie ma znaczenia, jakie są wartości (użyłeś 0, 1, 2), użyłbym znaczącego ciągu znaków w przypadku, gdybyś kiedykolwiek chciał wypisać bieżącą wartość.

 585
Author: Gareth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-13 19:22:44

Aktualizacja: dzięki za wszystkie upvotes wszyscy, ale nie sądzę, moja odpowiedź poniżej jest najlepszym sposobem, aby pisać enums w Javascript już. Zobacz mój wpis na blogu po więcej szczegółów: Enums in Javascript .


Alarmowanie nazwy jest już możliwe:

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

Alternatywnie, można zrobić obiekty wartości, więc można mieć ciasto i zjeść go zbyt:

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

W Javascript, ponieważ jest to język dynamiczny, możliwe jest nawet dodanie wartości enum do zestawu później:

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

Pamiętaj, że pola enum (wartość, nazwa i kod w tym przykładzie) nie są potrzebne do sprawdzenia tożsamości i są tam tylko dla wygody. Również sama nazwa właściwości size nie musi być zakodowana na twardo, ale może być również ustawiana dynamicznie. Więc przypuśćmy, że znasz tylko nazwę dla nowej wartości enum, nadal możesz dodać ją bez problemów:

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

Oczywiście oznacza to, że pewnych założeń nie da się już zrealizować (wartość ta reprezentuje poprawną zamówienie na rozmiar np.).

Pamiętaj, że w Javascript obiekt jest jak mapa lub hashtable. Zestaw par nazwa-wartość. Możesz je przeglądać lub w inny sposób nimi manipulować, nie wiedząc o nich zbyt wiele z góry.

Np:

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

I btw, jeśli jesteś zainteresowany przestrzeniami nazw, możesz rzucić okiem na moje rozwiązanie dla prostej, ale potężnej przestrzeni nazw i zarządzania zależnościami dla javascript: Packages JS

 480
Author: Stijn de Witt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-09 18:41:26

Reasumując: nie możesz.

Możesz udawać, ale nie dostaniesz bezpieczeństwa. Zazwyczaj odbywa się to poprzez utworzenie prostego słownika wartości ciągów odwzorowanych na wartości całkowite. Na przykład:
var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}

Document.Write("Enumerant: " + DaysEnum.tuesday);

Problem z tym podejściem? Można przypadkowo przedefiniować swój enumerant lub przypadkowo mieć zduplikowane wartości enumerant. Na przykład:

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

Edit

A co z obiektem Artura Czajki?zamrozić? Czy to nie przeszkodzi ci w od poniedziałku do czwartku? - Fry Quad

Absolutnie, Object.freeze całkowicie rozwiąże problem, na który narzekałem. Chciałbym przypomnieć wszystkim, że kiedy pisałem wyżej, Object.freeze tak naprawdę nie istniał.

Teraz.... teraz otwiera kilka bardzo interesujących możliwości.

Edit 2
Oto bardzo dobra biblioteka do tworzenia enum.

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

Chociaż prawdopodobnie nie pasuje do każdego poprawnego użycia enum, przechodzi bardzo długą drogę.

 80
Author: Randolpho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-06 16:09:02

Oto czego wszyscy chcemy:

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

Teraz możesz tworzyć swoje enums:

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

W ten sposób, stałe mogą być accessed w zwykły sposób (YesNo.Tak, Kolor.Zielony) i otrzymują sekwencyjną wartość int (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

Możesz również dodać metody, używając Enum.prototyp:

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


Edit-mała poprawa - teraz z varargs: (niestety nie działa poprawnie na IE: S... powinien pozostać przy poprzedniej wersji then)

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

var YesNo = new Enum('NO', 'YES');
var Color = new Enum('RED', 'GREEN', 'BLUE');
 46
Author: Andre 'Fi',
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-19 01:21:59

W większości nowoczesnych przeglądarek istnieje symbol prymitywny typ danych, który może być używany do tworzenia wyliczeń. Zapewni to bezpieczeństwo typu enum, ponieważ każda wartość symbolu jest gwarantowana przez JavaScript jako unikalna, tzn. Symbol() != Symbol(). Na przykład:

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

Aby uprościć debugowanie, możesz dodać opis do wartości enum:

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

Plunker demo

Na GitHub znajdziesz wrapper, który upraszcza kod wymagany do zainicjowania enum:

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
 44
Author: Vitalii Fedorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-31 23:33:29

Bawiłem się tym, ponieważ kocham moje wyliczenia. =)

Używając Object.defineProperty myślę, że wpadłem na dość realne rozwiązanie.

Oto jsfiddle: http://jsfiddle.net/ZV4A6/

Za pomocą tej metody.. powinieneś (teoretycznie) być w stanie wywołać i zdefiniować wartości enum dla dowolnego obiektu, bez wpływu na inne atrybuty tego obiektu.

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

Ze względu na atrybut writable:false Ten powinien uczynić Typ bezpiecznym.

Więc powinieneś być w stanie Utwórz obiekt niestandardowy, a następnie wywołaj na nim Enum(). Przypisane wartości rozpoczynają się od 0 i przyrostu dla każdej pozycji.

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3
 23
Author: Duncan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-21 17:20:55

Jest to stary, który znam, ale sposób, w jaki został zaimplementowany za pomocą interfejsu TypeScript to:

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

Pozwala to sprawdzić zarówno MyEnum.Bar, która zwraca 1, jak i MyEnum[1], która zwraca " Bar " niezależnie od kolejności deklaracji.

 18
Author: Rob Hardy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-24 16:11:14

To jest rozwiązanie, którego używam.

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

I definiujesz swoje enums tak:

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

I tak masz dostęp do swoich enum:

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

Zwykle używam ostatnich 2 metod do mapowania enum z obiektów wiadomości.

Niektóre zalety tego podejścia:

  • łatwe deklarowanie enum
  • łatwy dostęp do Twoich enum
  • twoje liczby mogą być typami złożonymi
  • Klasa Enum ma pewne asocjacyjne buforowanie, jeśli używasz getByValue a Nr serii

Niektóre wady:

  • niektóre bałagan zarządzania pamięcią dzieje się tam, jak zachować odniesienia do enum
  • nadal brak bezpieczeństwa typu
 15
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-15 09:31:57

Jeśli używasz Backbone , możesz uzyskać pełnowymiarową funkcjonalność enum (Znajdź według id, nazwy, niestandardowych członków) za darmo używając Backbone.Kolekcja .

// 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()
 12
Author: Yaroslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-24 14:04:46

W ES7 można wykonać eleganckie wyliczenie opierając się na atrybutach statycznych:

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

Then

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

Zaletą (używania klasy zamiast dosłownego obiektu) jest posiadanie klasy nadrzędnej Enum wtedy wszystkie Twoje Enums będą rozszerzać tę klasę.

 class ColorEnum  extends Enum {/*....*/}
 12
Author: Abdennour TOUMI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 07:07:59

Utwórz obiekt dosłowny:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};
 11
Author: hvdd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-01 17:03:41

"udoskonalona składnia" przez większość ludzi została już wymieniona powyżej. Istnieje jednak poważny problem nadrzędny: wydajność. Żadna z powyższych odpowiedzi nie jest bardzo wydajna w najmniejszym stopniu i wszystkie nadmuchują twój rozmiar kodu do skrajności. Aby uzyskać rzeczywistą wydajność, łatwość czytania kodu i bezprecedensowe zmniejszenie rozmiaru kodu przez minifikację, jest to prawidłowy sposób na wyliczenia.

const ENUM_COLORENUM_RED   = 0,
      ENUM_COLORENUM_GREEN = 1,
      ENUM_COLORENUM_BLUE  = 2,
      ENUMLEN_COLORENUM    = 3;

// later on

if(currentColor == ENUM_COLORENUM_RED) {
   // whatever
}

Dodatkowo składnia ta pozwala na jasne i zwięzłe rozszerzenie klasy jak widać poniżej.

(Długość: 2450 bajtów)

(function(window){
    "use strict";
    var parseInt = window.parseInt

    const ENUM_PIXELCOLOR_TYPE = 0, // is a ENUM_PIXELTYPE
          ENUMLEN_PIXELCOLOR   = 1,
          ENUM_SOLIDCOLOR_R    = ENUMLEN_PIXELCOLOR+0,
          ENUM_SOLIDCOLOR_G    = ENUMLEN_PIXELCOLOR+1,
          ENUM_SOLIDCOLOR_B    = ENUMLEN_PIXELCOLOR+2,
          ENUMLEN_SOLIDCOLOR   = ENUMLEN_PIXELCOLOR+3,
          ENUM_ALPHACOLOR_R    = ENUMLEN_PIXELCOLOR+0,
          ENUM_ALPHACOLOR_G    = ENUMLEN_PIXELCOLOR+1,
          ENUM_ALPHACOLOR_B    = ENUMLEN_PIXELCOLOR+2,
          ENUM_ALPHACOLOR_A    = ENUMLEN_PIXELCOLOR+3,
          ENUMLEN_ALPHACOLOR   = ENUMLEN_PIXELCOLOR+4,
          ENUM_PIXELTYPE_SOLID = 0,
          ENUM_PIXELTYPE_ALPHA = 1,
          ENUM_PIXELTYPE_UNKNOWN = 2,
          ENUMLEN_PIXELTYPE    = 2;

    function parseHexColor(rawstr) {
        rawstr = rawstr.trim().substring(1);
        var result = [];
        if (rawstr.length === 8) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA;
            result[ENUM_ALPHACOLOR_R] = parseInt(rawstr.substring(0,2), 16);
            result[ENUM_ALPHACOLOR_G] = parseInt(rawstr.substring(2,4), 16);
            result[ENUM_ALPHACOLOR_B] = parseInt(rawstr.substring(4,6), 16);
            result[ENUM_ALPHACOLOR_A] = parseInt(rawstr.substring(4,6), 16);
        } else if (rawstr.length === 4) {
            result[ENUM_ALPHACOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
            result[ENUM_ALPHACOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
            result[ENUM_ALPHACOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
            result[ENUM_ALPHACOLOR_A] = parseInt(rawstr[3], 16) * 0x11;
        } else if (rawstr.length === 6) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
            result[ENUM_SOLIDCOLOR_R] = parseInt(rawstr.substring(0,2), 16);
            result[ENUM_SOLIDCOLOR_G] = parseInt(rawstr.substring(2,4), 16);
            result[ENUM_SOLIDCOLOR_B] = parseInt(rawstr.substring(4,6), 16);
        } else if (rawstr.length === 3) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
            result[ENUM_SOLIDCOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
            result[ENUM_SOLIDCOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
            result[ENUM_SOLIDCOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
        } else {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_UNKNOWN;
        }
        return result;
    }

    // the red component of green
    console.log(parseHexColor("#0f0")[ENUM_SOLIDCOLOR_R]);
    // the alpha of transparent purple
    console.log(parseHexColor("#f0f7")[ENUM_ALPHACOLOR_A]); 
    // the enumerated array for turquoise
    console.log(parseHexColor("#40E0D0"));
})(self);
Niektórzy mogą powiedzieć, że jest to mniej praktyczne niż inne rozwiązania: zajmuje mnóstwo miejsca, zajmuje dużo czasu, a jego składnia nie jest pokryta cukrem. Tak, ci ludzie mieliby rację, gdyby nie zminimalizowali swojego kodu. Jednak żadna rozsądna osoba nie zostawiłaby niezminifikowanego kodu w produkcie końcowym. Dla tej minifikacji, Closure Compiler jest najlepszym, jakiego jeszcze nie znalazłem. Dostęp Online można znaleźć tutaj . Closure compiler jest w stanie wziąć wszystkie te dane wyliczenia i wbudować je, dzięki czemu javascript działa super duper szybko i być Super duper mały. Obserwuj.

(Długość: 605 bajtów)

'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);

Teraz zobaczmy, jak duży byłby plik równoważny bez żadnego z tych wyliczeń.

Source Without Enumerations (length: 1,973 bytes (shorter!))
Minified Without Enumerations (length: 843 bytes ( longer))

Jak widać, bez wyliczeń, kod źródłowy jest krótszy kosztem większego zminifikowanego kodu. Nie wiem jak wy, wiem na pewno, że nie lubię włączać kodu źródłowego do produktu końcowego, dzięki czemu to wyliczenie jest o wiele lepsze. Dodaj do tego, że ta forma wyliczenia jest o wiele szybsza. Rzeczywiście, ta forma wyliczenia jest drogą do zrobienia.

 10
Author: Jack Giffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 10:30:16

Twoje odpowiedzi są zbyt skomplikowane.]}

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
 9
Author: Xeltor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-15 04:20:02

Zmodyfikowałem rozwiązanie Andre 'Fi':

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

Test:

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
 8
Author: David Miró,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-12 17:04:16

Użyj Javascript Proxy

Jedną z bardzo korzystnych cech Enum, które otrzymujesz z tradycyjnych języków, jest to, że wybuchają (rzucają błąd w czasie kompilacji), jeśli próbujesz uzyskać dostęp do enumeratora, który nie istnieje.

Poza zamrożeniem wyśmiewanej struktury enum, aby zapobiec przypadkowemu / złośliwemu dodaniu dodatkowych wartości, żadna z innych odpowiedzi nie odnosi się do tej wewnętrznej cechy Enum.

Jak zapewne wiesz, dostęp do nieistniejących członków w JavaScript po prostu zwraca undefined i nie wysadza kodu. Ponieważ enumeratory są predefiniowanymi stałymi (np. dni tygodnia), nigdy nie powinno być przypadków, w których enumerator powinien być niezdefiniowany.

Nie zrozum mnie źle, zachowanie JavaScript zwracające undefined podczas uzyskiwania dostępu do niezdefiniowanych właściwości jest w rzeczywistości bardzo potężną cechą języka, ale nie jest to funkcja, którą chcesz, gdy próbujesz wyśmiewać tradycyjne struktury Enum.

Tutaj świecą Obiekty Proxy. Proxy zostały standaryzowane w języku wraz z wprowadzeniem ES6 (ES2015). Oto opis z MDN:

Obiekt Proxy jest używany do definiowania niestandardowego zachowania dla podstawowych operacji (np. wyszukiwanie właściwości, przypisywanie, wyliczanie, funkcja inwokacji itp.).

Podobnie jak proxy serwera www, proxy JavaScript są w stanie przechwytywać operacje na obiektach (za pomocą "pułapek", nazywaj je hookami, jeśli chcesz) i pozwalają na wykonywanie różnych kontroli, działania i / lub manipulacje przed ich zakończeniem (lub w niektórych przypadkach całkowite zatrzymanie operacji, co jest dokładnie tym, co chcemy zrobić, jeśli i kiedy próbujemy odwołać się do wyliczenia, które nie istnieje).

Oto wymyślony przykład, który używa obiektu Proxy do naśladowania liczb. Wyliczenia w tym przykładzie są standardowymi metodami HTTP (tzn. "GET", "POST", itd.):

// Generic Factory Function for creating enums (10 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

function createEnum(enumObj) {

  // 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. This can be done by defining the "get" trap
  
  const enumHandler = {
    get: function(target, name) {
      if (target[name]) {
        return target[name]
      }
      throw new Error(`No such enumerator: ${name}`)
    }
  }
  
  
  // Freeze the target object to prevent modifications
  return new Proxy(Object.freeze(enumObj), enumHandler)
}


// Now that we have a generic way of creating Enums, lets create our first Enum!
const httpMethods = createEnum({
  DELETE: "DELETE",
  GET: "GET",
  OPTIONS: "OPTIONS",
  PATCH: "PATCH",
  POST: "POST",
  PUT: "PUT"
})

// Sanity checks
console.log(httpMethods.DELETE) 
// logs "DELETE"

httpMethods.delete = "delete" 
// no effect due to Object.freeze, fails silently (no error thrown)

try {
  console.log(httpMethods.delete) 
} catch (e) {
  console.log("Error: ", e.message)
}
// throws an error "Uncaught Error: No such enumerator: delete"

Na marginesie: Co to do cholery jest proxy?

I remember when I po raz pierwszy zobaczyłem słowo proxy wszędzie, zdecydowanie nie miało to dla mnie sensu przez długi czas. Jeśli to teraz ty, myślę, że łatwym sposobem na uogólnienie proxy jest myślenie o nich jako o oprogramowaniu, instytucjach, a nawet ludziach, którzy działają jako pośrednicy lub pośrednicy między dwoma serwerami, firmami lub ludźmi.

 7
Author: Govind Rai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 03:11:13

IE8 nie obsługuje metody freeze ().
Źródło: http://kangax.github.io/compat-table/es5 / , Kliknij "Pokaż przestarzałe przeglądarki?"na górze i sprawdź IE8 i zamrozić row col.

W moim obecnym projekcie gry, użyłem poniżej, ponieważ niewielu klientów nadal korzysta z IE8:

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

Możemy również zrobić:

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

Albo nawet to:

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

Ostatni, wydaje się najbardziej wydajny dla string, zmniejsza całkowitą przepustowość, jeśli masz serwer i klienta wymiana tych danych.
Oczywiście teraz twoim obowiązkiem jest upewnienie się, że nie ma konfliktów w danych (RE, EX itp. musi być unikalny, także 1, 2 itp. powinny być unikalne). Zauważ, że musisz je zachować na zawsze, aby zachować kompatybilność wsteczną.

Przypisanie:

var wildType = CONST_WILD_TYPES.REGULAR;

Porównanie:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}
 5
Author: Manohar Reddy Poreddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 04:50:50

Stworzyłem klasę Enum, która może pobierać wartości i nazwy w O(1). Może również wygenerować tablicę obiektów zawierającą wszystkie nazwy i wartości.

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

Możesz to zrobić tak:

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

Aby pobrać wartość (jak Enums w C#):

var val2 = enum1.item2;

Aby pobrać nazwę dla wartości (może być niejednoznaczne przy umieszczaniu tej samej wartości dla różnych nazw):

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

Aby uzyskać tablicę z każdą nazwą i wartością w obiekcie:

var arr = enum1.GetObjArr();

Wygeneruje:

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

Można również uzyskać opcje wyboru html:

var html = enum1.GetSelectOptionsHTML();

Który posiada:

"<option value='0'>item1</option>..."
 5
Author: Oooogi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-08 18:22:27

Szybkim i prostym sposobem byłoby:

var Colors = function(){
return {
    'WHITE':0,
    'BLACK':1,
    'RED':2,
    'GREEN':3
    }
}();

console.log(Colors.WHITE)  //this prints out "0"
 4
Author: user2254487,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-06 22:07:47

Oto kilka różnych sposobów implementacji liczb maszynopisu .

Najprostszym sposobem jest iteracja nad obiektem, dodanie do obiektu odwróconych par klucz-wartość. Jedyną wadą jest to, że musisz ręcznie ustawić wartość dla każdego członka.

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


A oto lodash mixin do tworzenia enum za pomocą ciągu znaków. Chociaż ta wersja jest trochę bardziej zaangażowana, robi numerację automatycznie za Ciebie. Wszystkie metody lodash użyte w tym przykładzie mają zwykły odpowiednik JavaScript, dzięki czemu można je łatwo przełączyć, jeśli chcesz.

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
 4
Author: Blake Bowen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-17 21:24:32

Właśnie opublikowałem pakiet npm gen_enum pozwala na szybkie tworzenie struktury danych Enum w 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 

Miłą rzeczą w tym małym narzędziu jest to, że we współczesnym środowisku (włącznie z przeglądarkami nodejs i IE 9+) zwracany obiekt Enum jest niezmienny.

Aby uzyskać więcej informacji prosimy o zamówienie https://github.com/greenlaw110/enumjs

Aktualizacje

I gen_enum pakiet i scalić funkcję do constjs pakiet, który zawiera więcej funkcji, w tym obiekty niezmienne, deserializację łańcuchów JSON, stałe łańcuchowe i generowanie bitmap itp. Checkout https://www.npmjs.com/package/constjs Więcej informacji

Aby uaktualnić z gen_enum do constjs wystarczy zmienić instrukcję

var genEnum = require('gen_enum');

Do

var genEnum = require('constjs').enum;
 4
Author: Gelin Luo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 23:44:40

Wymyśliłemto podejście, które jest wzorowane na enumach w Javie. Są one bezpieczne dla typu, więc można również wykonywać instanceof kontrole.

Możesz zdefiniować liczby w następujący sposób:

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

Days teraz odnosi się do Days enum:

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"

Realizacja:

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
    }

})();
 4
Author: Vivin Paliath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-18 22:11:20

Mimo że tylko statyczne metody (a nie statyczne właściwości) są obsługiwane w ES2015 (zobacz tutaj, jak również, §15.2.2.2), co ciekawe, możesz użyć poniższego z Babel z presetem 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);

Okazało się, że działa to zgodnie z oczekiwaniami nawet w modułach (np. importowanie enum CellState z innego modułu), a także podczas importowania modułu za pomocą Webpack.

Zaletą tej metody w stosunku do większości innych odpowiedzi jest to, że można jej używać obok static type checker (np. Flow ) i możesz stwierdzić, w czasie tworzenia za pomocą statycznego type checking, że Twoje zmienne, parametry itp. są ze specyficznego CellState "enum", a nie jakiegoś innego enum (które byłoby niemożliwe do odróżnienia, gdyby użyto ogólnych obiektów lub symboli).

Update

Powyższy kod ma wadę w tym, że pozwala na tworzenie dodatkowych obiektów typu CellState (nawet jeśli nie można przypisać ich do statycznych pól CellState ponieważ jest zamrożony). Jednak poniższy bardziej dopracowany kod oferuje następujące zalety:]}

  1. nie można tworzyć więcej obiektów typu CellState
  2. masz gwarancję, że żadne dwie instancje enum nie będą przypisane do tego samego kodu
  3. metoda użytkowa, aby uzyskać enum z powrotem z reprezentacji string
  4. Funkcja values zwracająca wszystkie instancje enum nie musi tworzyć wartości zwracanej w powyższym podręczniku (i podatnej na błędy) sposób.

    '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;
    
 4
Author: Marcus Junius Brutus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-23 22:38:00

W chwili pisania, Październik 2014 - Oto współczesne rozwiązanie. Piszę rozwiązanie jako moduł węzłowy, a w nim test z użyciem Mocha i Chai, a także podkreślenia. Możesz je łatwo zignorować i po prostu wziąć kod Enum, jeśli jest to preferowane.

Widziałem wiele postów z zbyt zawiłymi bibliotekami itp. Rozwiązanie do uzyskania wsparcia enum w Javascript jest tak proste, że naprawdę nie jest potrzebne. Oto kod:

Plik: enums.js

_ = require('underscore');

var _Enum = function () {

   var keys = _.map(arguments, function (value) {
      return value;
   });
   var self = {
      keys: keys
   };
   for (var i = 0; i < arguments.length; i++) {
      self[keys[i]] = i;
   }
   return self;
};

var fileFormatEnum = Object.freeze(_Enum('CSV', 'TSV'));
var encodingEnum = Object.freeze(_Enum('UTF8', 'SHIFT_JIS'));

exports.fileFormatEnum = fileFormatEnum;
exports.encodingEnum = encodingEnum;

I test aby zilustrować co daje:

Plik: enumsSpec.js

var chai = require("chai"),
    assert = chai.assert,
    expect = chai.expect,
    should = chai.should(),
    enums = require('./enums'),
    _ = require('underscore');


describe('enums', function () {

    describe('fileFormatEnum', function () {
        it('should return expected fileFormat enum declarations', function () {
            var fileFormatEnum = enums.fileFormatEnum;
            should.exist(fileFormatEnum);
            assert('{"keys":["CSV","TSV"],"CSV":0,"TSV":1}' === JSON.stringify(fileFormatEnum), 'Unexpected format');
            assert('["CSV","TSV"]' === JSON.stringify(fileFormatEnum.keys), 'Unexpected keys format');
        });
    });

    describe('encodingEnum', function () {
        it('should return expected encoding enum declarations', function () {
            var encodingEnum = enums.encodingEnum;
            should.exist(encodingEnum);
            assert('{"keys":["UTF8","SHIFT_JIS"],"UTF8":0,"SHIFT_JIS":1}' === JSON.stringify(encodingEnum), 'Unexpected format');
            assert('["UTF8","SHIFT_JIS"]' === JSON.stringify(encodingEnum.keys), 'Unexpected keys format');
        });
    });

});

Jak widzisz, dostajesz fabrykę Enum, możesz uzyskać wszystkie klucze po prostu wywołując enum.klucze, i możesz dopasować same klucze do stałych całkowitych. Możesz też ponownie użyć fabryki z różnymi wartościami i wyeksportować wygenerowane liczby za pomocą podejścia modułowego węzła.

Jeszcze raz, jeśli jesteś zwykłym użytkownikiem, lub w przeglądarce itp., Po prostu weź fabryczną część kodu, potencjalnie usuwając biblioteka podkreślenia również, jeśli nie chcesz jej używać w kodzie.

 3
Author: arcseldon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-20 17:44:48
var ColorEnum = {
    red: {},
    green: {},
    blue: {}
}

Nie musisz się upewnić, że nie przypisujesz zduplikowanych liczb do różnych wartości enum w ten sposób. Nowy obiekt zostanie utworzony i przypisany do wszystkich wartości enum.

 3
Author: Shivanshu Goyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-29 01:32:23

Możesz zrobić coś takiego

function Enum(){
  this.add.apply(this,arguments);
}

Enum.prototype.add = function(){
  for (var i in arguments) {
    this[arguments[i]] = new String(arguments[i]);
  }
};
Enum.prototype.toList = function(){
  return Object.keys(this)
};

var STATUS = new Enum("CLOSED","PENDING");


var STATE = new Enum("CLOSED","PENDING");

STATE.CLOSED === STATUS.CLOSED  // false;
STATE.CLOSED === "CLOSED"  // false;
STATE.CLOSED.toString() === "CLOSED"  // true;

Jak zdefiniowano w tej bibliotece. https://github.com/webmodule/foo/blob/master/foo.js#L217

 3
Author: LNT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 06:32:25

Najprostsze rozwiązanie:

Utwórz

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

Get Value

console.log(Status.Ready) // 1

Pobierz Klucz

console.log(Object.keys(Status)[Status.Ready]) // Ready
 3
Author: Ilya Gazman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-17 12:38:45

Tak Typescript tłumaczy to enum Na Javascript:

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

Teraz:

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

Początkowo byłem zdezorientowany dlaczego obj[1] zwraca 'Active', ale potem zdałem sobie sprawę, że jego martwy prosty operator - przypisanie przypisuje wartość i zwraca ją:

obj['foo'] = 1
// => 1
 3
Author: Julius Dzidzevičius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-03 18:44:59

Zrobiłem to jakiś czas temu używając mieszanki __defineGetter__ i __defineSetter__ lub defineProperty w zależności od wersji JS.

Oto funkcja generująca enum, którą wykonałem: https://gist.github.com/gfarrell/6716853

Użyłbyś tego Tak:

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

I tworzy niezmienny ciąg znaków: int dictionary (an enum).

 2
Author: GTF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 17:04:01

Myślę, że jest łatwy w użyciu. https://stackoverflow.com/a/32245370/4365315

var A = {a:11, b:22}, 
enumA = new TypeHelper(A);

if(enumA.Value === A.b || enumA.Key === "a"){ 
... 
}

var keys = enumA.getAsList();//[object, object]

//set
enumA.setType(22, false);//setType(val, isKey)

enumA.setType("a", true);

enumA.setTypeByIndex(1);

Aktualizacja:

Oto moje kody pomocnicze (TypeHelper).

var Helper = {
    isEmpty: function (obj) {
        return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
    },

    isObject: function (obj) {
        return (typeof obj === 'object');
    },

    sortObjectKeys: function (object) {
        return Object.keys(object)
            .sort(function (a, b) {
                c = a - b;
                return c
            });
    },
    containsItem: function (arr, item) {
        if (arr && Array.isArray(arr)) {
            return arr.indexOf(item) > -1;
        } else {
            return arr === item;
        }
    },

    pushArray: function (arr1, arr2) {
        if (arr1 && arr2 && Array.isArray(arr1)) {
            arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
        }
    }
};
function TypeHelper() {
    var _types = arguments[0],
        _defTypeIndex = 0,
        _currentType,
        _value,
        _allKeys = Helper.sortObjectKeys(_types);

    if (arguments.length == 2) {
        _defTypeIndex = arguments[1];
    }

    Object.defineProperties(this, {
        Key: {
            get: function () {
                return _currentType;
            },
            set: function (val) {
                _currentType.setType(val, true);
            },
            enumerable: true
        },
        Value: {
            get: function () {
                return _types[_currentType];
            },
            set: function (val) {
                _value.setType(val, false);
            },
            enumerable: true
        }
    });
    this.getAsList = function (keys) {
        var list = [];
        _allKeys.forEach(function (key, idx, array) {
            if (key && _types[key]) {

                if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) {
                    var json = {};
                    json.Key = key;
                    json.Value = _types[key];
                    Helper.pushArray(list, json);
                }
            }
        });
        return list;
    };

    this.setType = function (value, isKey) {
        if (!Helper.isEmpty(value)) {
            Object.keys(_types).forEach(function (key, idx, array) {
                if (Helper.isObject(value)) {
                    if (value && value.Key == key) {
                        _currentType = key;
                    }
                } else if (isKey) {
                    if (value && value.toString() == key.toString()) {
                        _currentType = key;
                    }
                } else if (value && value.toString() == _types[key]) {
                    _currentType = key;
                }
            });
        } else {
            this.setDefaultType();
        }
        return isKey ? _types[_currentType] : _currentType;
    };

    this.setTypeByIndex = function (index) {
        for (var i = 0; i < _allKeys.length; i++) {
            if (index === i) {
                _currentType = _allKeys[index];
                break;
            }
        }
    };

    this.setDefaultType = function () {
        this.setTypeByIndex(_defTypeIndex);
    };

    this.setDefaultType();
}

var TypeA = {
    "-1": "Any",
    "2": "2L",
    "100": "100L",
    "200": "200L",
    "1000": "1000L"
};

var enumA = new TypeHelper(TypeA, 4);

document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setType("200L", false);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

enumA.setDefaultType();
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setTypeByIndex(1);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

document.writeln("is equals = ", (enumA.Value == TypeA["2"]));
 2
Author: Sherali Turdiyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32