JavaScript'te numaralandırma tanımlamak için tercih edilen sözdizimi nedir?


2082

JavaScript'te numaralandırma tanımlamak için tercih edilen sözdizimi nedir? Gibi bir şey:

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

// later on

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

Yoksa daha çok tercih edilen bir deyim var mı?


131
0Numaralandırma numarası olarak kullanmayın . Ayarlanmamış bir şey için kullanılmadığı sürece. JS, kullanımı ile karşılaştırıldığında false || undefined || null || 0 || "" || '' || NaNhepsine aynı değer olarak davranır ==.
matsko

152
@matsko sadece == kullanmaya karşı bir argüman değil mi?
sdm350

6
0 == nullyanlış döndürür
mcont

11
Ancak false == 0ve +null == 0(ve sayılara dönüşüm bazen beklemediğinizde gerçekleşir) null == undefined, ve +undefinedaynı zamanda NaN( ve NaN != NaN).
sanderd17

46
Çifte eşitlik matrisi, microsoft word'ün otomatik biçimlendirmesinden daha kafa karıştırıcı
aaaaaa

Yanıtlar:


896

1.8.5'ten beri nesneyi mühürlemek ve dondurmak mümkündür, bu yüzden yukarıdakileri şu şekilde tanımlayın:

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

veya

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

ve işte! JS sıralamaları.

Bununla birlikte, bu, genellikle numaralandırmaların ana hedefi olan bir değişkene istenmeyen bir değer atamanızı engellemez:

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

Daha güçlü bir tip güvenliği (numaralandırmalarla veya başka bir yöntemle) sağlamanın bir yolu, TypeScript veya Flow gibi bir araç kullanmaktır .

Kaynak

Alıntılara gerek yok ama tutarlılık için onları sakladım.


6
Wikipedia'ya göre ( en.wikipedia.org/wiki/JavaScript#Versions ) Firefox 4, IE 9, Opera 11.60 için geçerlidir ve Chrome'da çalıştığını biliyorum.
Artur Czajka

77
Bu 2012'de Daha basit artık doğru cevaptır: var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });. Bir kimlik belirtmeniz gerekmez, yalnızca numaralandırmaları karşılaştırmak için boş bir nesne kullanabilirsiniz. if (incommingEnum === DaysEnum.monday) //incommingEnum is monday
Gabriel Llamas

34
Geriye dönük uyumluluk içinif (Object.freeze) { Object.freeze(DaysEnum); }
Ağustos'ta

17
Bunu yapmak ({ monday: {}, vb. İşaret etmek istiyorum, eğer o nesneyi stringize ile JSON'a dönüştürürseniz, [{"day": {}}]işe yaramayacaksınız demektir.
jcollum

10
@Supuhstar Bu soru hakkındaki görüşüm şimdi farklı. Freeze () kullanmayın, tamamen işe yaramaz ve "aptal" şeyler yapmak zaman kaybıdır. Bir enum açığa istiyorsanız, sadece bu açığa: var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}. Önceki yorumumda olduğu gibi nesneleri karşılaştırmak, sayıları karşılaştırmaktan çok daha zayıf.
Gabriel Llamas

608

Bu bir cevap değil, ama kişisel olarak iyi çalıştığını söyleyebilirim

Söyledikten sonra, değerlerin ne olduğu önemli değil (0, 1, 2 kullandınız), şimdiki değeri çıkarmak istediğinizde anlamlı bir dize kullanacağım.


377
Bu başka bir cevapta ifade edildi, ancak bu cevap kabul edilen cevap olduğu için bunu buraya göndereceğim. OP'nin çözümü doğrudur. Bununla birlikte, kullanıldığında daha da iyi olacaktır Object.freeze(). Bu, diğer kodun enum değerlerini değiştirmesini önleyecektir. Örnek:var ColorEnum = Object.freeze({RED: 0, GREEN: 1, BLUE: 2});
Sildoreth

5
@TolgaE bu kütüphane için teşekkürler! Sadece çıplak minimum kaynatmak değil, aynı zamanda birkaç özellik eklemek için bana ilham verdi! Seninkini çatalladım
Supuhstar

3
@Supuhstar Harika! Kullanabileceğinize sevindim .. Bu kütüphanede birleştirilmesini istiyorsanız çekinme isteğinde bulunmaktan çekinmeyin, o zaman npm kütüphanesini güncelleyebilirim
Tolga E

2
Herkes ilgileniyorsa, Java'da olduklarına benzer tipte güvenli numaralandırmalar uyguladım . Bu, instanceofkontroller yapabileceğiniz anlamına gelir . Örneğin ColorEnum.RED instanceof ColorEnum(iadeler true). Ayrıca bir ismin bir örneğini dışarı çözebilirsiniz ColorEnum.fromName("RED") === ColorEnum.RED(döner true). Her örnek ayrıca bir .name()ve .ordinal()yöntemine sahiptir ve values()enum'un kendisi, tüm sabitlerin bir dizisini geri dönen bir yönteme sahiptir.
Vivin Paliath

3
"Anlamlı dize" öneri ile kabul emin değilim. Numaralamalar dize veya sayı olarak düşünülmemelidir; bunlar soyut veri tipleridir. Bazı yardımcı yöntemler olmadan "akım değerini çıktılamak" mümkün olmamalıdır. Java ve .NET'te bu ToString()yöntemdir. Biz JS devs zaten "sadece çalışma" şeylere çok güven vardır! Ayrıca, kişi hızlı switchbir şekilde bir enum üzerinde yapabilmelidir . Dizeleri karşılaştırmak sayıları karşılaştırmaktan daha yavaştır, bu nedenle switchtamsayılar yerine dizeler kullanırsanız biraz daha kötü performans elde edersiniz .
Rabadash8820

501

GÜNCELLEME

Herkesin tüm oyları için teşekkürler, ancak aşağıdaki cevabımın artık JavaScript'te enum yazmanın en iyi yolu olduğunu düşünmüyorum. Daha fazla ayrıntı için blog gönderime bakın: JavaScript'teki numaralandırmalar .


Adı uyarmak zaten mümkündür:

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

Alternatif olarak, değerler nesnelerini yapabilir, böylece pastayı alabilir ve de yiyebilirsiniz:

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'te, dinamik bir dil olduğundan, daha sonra kümeye numaralandırma değerleri eklemek bile mümkündür:

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

Unutmayın, numaralandırma alanlarına (bu örnekteki değer, ad ve kod) kimlik kontrolü için gerekli değildir ve yalnızca kolaylık sağlamak için vardır. Ayrıca size özelliğinin adının sabit kodlanması gerekmez, ancak dinamik olarak da ayarlanabilir. Bu nedenle, yalnızca yeni numaralandırma değerinizin adını bildiğinizi varsayalım, yine de sorunsuz bir şekilde ekleyebilirsiniz:

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

Tabii ki bu, bazı varsayımların artık yapılamayacağı anlamına gelir (bu değer, örneğin boyut için doğru siparişi temsil eder).

Unutmayın, JavaScript'te bir nesne bir harita veya karma tablosu gibidir . Bir dizi ad-değer çifti. Önceden çok fazla şey bilmeden, bunlar arasında dolaşabilir veya başka şekilde manipüle edebilirsiniz.

Misal

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

Bu arada, ad alanlarıyla ilgileniyorsanız, JavaScript için basit ama güçlü ad alanı ve bağımlılık yönetimi için çözümüme göz atmak isteyebilirsiniz: Packages JS


öyleyse sadece isminiz varsa nasıl bir SIZE oluşturabilirdiniz?
Johanisma

2
@Johanisma: Bu kullanım durumu, tüm fikirleri önceden bildiğiniz için numaralandırmalar için gerçekten mantıklı değildir. Ancak, daha sonra Javascript'te ekstra değerler eklemenizi engelleyen hiçbir şey yoktur. Cevabıma bunun bir örneğini ekleyeceğim.
Stijn de Witt

2
Özellikler yaklaşımı ile yayınınıza bağlantı için +1. Zarif, OP bildirimlerinde olduğu gibi basit bildirimlerin basit olması, istenildiğinde eklenen özellikler özelliğiyle.
goodeye

@Stijin, güncellenmiş çözümünüzü gerçekten beğendim. Blogunuzdaki yorumlarda ve aşağıda yorum olarak gönderilen kod. Temel olarak, bir işlev kullanarak, varolan bir karma listesinden özellikler derlemesi gerçekleştirin ve isteğe bağlı olarak dondurun (listemde mkenum_2). Şerefe.
Andrew Philips

Ayrıca, karşılaştırma ve ters arama ile ilgili güzel özellikler de dahil olmak üzere, onu uygulayan bir kütüphane de vardır: github.com/adrai/enum
Roman M

83

Alt satır: Yapamazsınız.

Sahte olabilirsiniz, ancak tip güvenliği alamazsınız. Genellikle bu, tamsayı değerlere eşlenmiş basit bir dize değerleri sözlüğü oluşturularak yapılır. Örneğin:

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}

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

Bu yaklaşımla ilgili sorun mu var? Kazandığınız kişiyi yanlışlıkla yeniden tanımlayabilir veya yanlışlıkla yinelenen sayıcı değerlerine sahip olabilirsiniz. Örneğin:

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

Düzenle

Artur Czajka'nın Object.freeze ne olacak? Bu, pazartesiden perşembeye gitmenizi engellemek için işe yaramaz mı? - Fry Dörtlü

Kesinlikle, Object.freeze tamamen şikayet ettiğim sorunu giderir. Herkese, yukarıda yazdığımda, Object.freezegerçekten var olmadığını hatırlatmak isterim .

Şimdi .... şimdi çok ilginç olasılıklar sunuyor.

Edit 2
İşte enums oluşturmak için çok iyi bir kütüphane.

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

Muhtemelen enumların her geçerli kullanımına uymuyor olsa da, çok uzun bir yol kat ediyor.


103
JavaScript tür güvenliği var mı?
Scott Evernden

3
Bu yüzden değerleri nesne özelliklerine eşlemeyin. Sayıcıya erişmek için alıcıyı kullanın (örneğin "özel" nesnenin bir özelliği olarak depolanır). Saf bir uygulama şöyle görünecektir -var daysEnum = (function(){ var daysEnum = { monday: 1, tuesday: 2 }; return { get: function(value){ return daysEnum[value]; } } })(); daysEnum.get('monday'); // 1
kanguru

2
@Scott Evernden: puan alındı. @kangax: önemli olan hala bir saldırı. Numaralandırmalar sadece Javascript, nokta, öykü sonunda mevcut değildir. Tim Sylvester tarafından önerilen desen bile hala ideal bir hack'ten daha az.
Randolpho

2
Kodun değişmez değerlerle serpilmesi çok sürdürülebilir değildir, bu nedenle bunun için sabitler oluşturmak mantıklıdır. Elbette Javascript'in sabitleri de yok. Temelde bu sadece temiz kod yazmanın bir yoludur. Uygulanamaz, ancak Javascript'te fazla bir şey olamaz. Sabitleri, fonksiyonları veya çoğunlukla herhangi bir şeyi yeniden tanımlayabilirsiniz. EG: document.getElementById = function () {alert ("Vidalısınız. Javascript typesafe değil.");};
Stijn de Witt

3
@Randolpho: Artur Czajka'nın Object.freeze ne olacak? Bu, pazartesiden perşembeye gitmenizi engellemek için işe yaramaz mı?
Michael - Clay Shirky

56

Hepimizin istediği:

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

Artık numaralandırmalarınızı oluşturabilirsiniz:

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

Bunu yaparak, sabitler olağan şekilde erişilebilir (YesNo.YES, Color.GREEN) ve sıralı bir int değeri alırlar (NO = 0, YES = 1; RED = 0, YEŞİL = 1, MAVİ = 2).

Enum.prototype kullanarak yöntemler de ekleyebilirsiniz:

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


Düzenleme - küçük iyileştirme - şimdi varargs ile: (ne yazık ki IE üzerinde düzgün çalışmıyor: S ... o zaman önceki sürümü ile sopa gerekir)

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

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

Bu cevabın basitliğini seviyorum!
Marquizzo

@Marquizzo (ve OP) Bu yanıta dayalı olarak geliştirilmiş bir sürüm oluşturdum: stackoverflow.com/a/60309416/1599699
Andrew

53

Çoğu modern tarayıcıda, bir numaralandırma oluşturmak için kullanılabilecek bir sembol ilkel veri türü vardır. Her sembol değerinin JavaScript tarafından benzersiz olması garanti edildiğinden, numaralandırmanın tür güvenliğini sağlayacaktır Symbol() != Symbol(). Örneğin:

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

Hata ayıklamayı basitleştirmek için değerleri numaralandırmaya bir açıklama ekleyebilirsiniz:

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

Plunker demosu

On GitHub'dan Eğer enum başlatmak için gerekli kodu basitleştiren bir sarmalayıcı bulabilirsiniz:

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

Teoride doğru cevap budur. Uygulamada, 2015 tarayıcı desteği yeterli olmaktan uzaktır. Üretim şimdiye kadar hazır değil.
vbraun

1
Tarayıcı desteği henüz mevcut olmasa da, bu en iyi yanıttır çünkü bu Symbolamaçlananlara yakındır .
rvighne

2
Bununla birlikte, enum değerlerinin genellikle serileştirilebilir olması gerekir ve Semboller serileştirmek ve serileştirmek için çok kullanışlı değildir.
Andy

3
Bu sadece ben mi yoksa Object.freezesadece "kendi sorumluluğunuzda maymunbalığı" nın JS'nin sosyal sözleşmesi olduğunu kabul etmeyen insanlar için mi?
Andy

@ Evet evet serileştirme can sıkıcı. Ben toJSONbu yaklaşımı kullanmak için içeren sınıfta bir açık yaparak sona erdi : stackoverflow.com/questions/58499828/…
Ciro Santilli 法轮功 病毒 审查 六四 事件 法轮功

30

𝗣𝗹𝗮𝗶𝗻 𝗩𝗮𝗻𝗶𝗹𝗹𝗮𝗝𝗦 𝗩𝗮𝗿𝗶𝗮𝗯𝗹𝗲 𝗡𝗮𝗺𝗲𝘀

Sorunu doğruca keselim: dosya boyutu. Burada listelenen diğer tüm cevaplar kodunuzu aşırı derecede şişirir. Size mümkün olan en iyi performans, kodun okunabilirliği, büyük ölçekli proje yönetimi, birçok kod editöründe sözdizimi ipucu ve kod boyutunun minyatürle azaltılması için numaralandırma yapmak için doğru yoldur: alt çizgi gösterim değişkenleri.


wvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwv

Alt Çizgi-Gösterim Değişkenleri

Yukarıdaki grafikte ve aşağıdaki örnekte gösterildiği gibi, başlamak için beş kolay adım şunlardır:

  1. Numaralandırma grubu için bir ad belirleyin. Sayımın amacını veya en azından sayımdaki girişleri tanımlayabilen bir isim düşünün. Örneğin, kullanıcı tarafından seçilebilen renkleri temsil eden bir grup numaralandırma, COLORCHOICES olarak COLOR'dan daha iyi adlandırılabilir.
  2. Gruptaki numaralandırmaların birbirini dışlayan veya bağımsız olup olmadığına karar verin. Karşılıklı olarak dışlanmışsa, numaralandırılmış her değişken adını ile başlatın ENUM_. Bağımsız veya yan yana ise kullanın INDEX_.
  3. Her giriş için adı ENUM_veya ile başlayan yeni bir yerel değişken oluşturun INDEX_, ardından grubun adı, ardından bir alt çizgi, ardından mülk için benzersiz bir kolay ad
  4. Bir ekleme ENUMLENGTH_, ENUMLEN_, INDEXLENGTH_veya INDEXLEN_(ister LEN_ya LENGTH_çok sonundadır kişisel tercih) sayılan değişkeni. Numaralandırmaya fazladan bir giriş eklemenin ve bu değerin artırılmasının kodunuzu kırmayacağından emin olmak için kodunuzda bu değişkeni mümkün olan her yerde kullanmalısınız.
  5. Diyelim ki bu sayfadaki yorum yapılmamış 0'dan başlamak üzere öncekinden daha birbirini izleyen her numaralandırılmış değişkeni bir değer tek ver 0bir sayılan değer çünkü olarak kullanılmamalıdır 0 == null, 0 == false, 0 == ""ve diğer JS delilik. Bu sorunu önlemek ve performansı aynı anda artırmak için, (ex ) dışında kodunuzda her zaman kullanın ===ve asla izin vermeyin . Kullandığım tüm yıllar boyunca, bir zamanlar numaralandırma değeri olarak 0'ı kullanmakla ilgili bir sorunum olmadı. Hala gıcırdayorsanız, birçok durumda performans cezası olmadan numaralandırmalarda (ancak numaralandırmalarda değil ) başlangıç ​​değeri olarak kullanılabilir .==typeoftypeof X == "string"===1ENUM_INDEX_
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
}

İşte ne zaman INDEX_ve ne zaman kullanacağımı hatırlıyorum ENUM_:

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

Ancak, ENUM_bazı durumlarda, her bir öğenin oluşumunu sayarken bir dizin olarak uygun olabilir.

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

Yukarıdaki kodda, yeni bir evcil hayvan türüne eklemek gerçekten kolay olduğunu gözlemleyin: sadece yeni bir giriş eklemeniz ENUM_PET_RATve ENUMLEN_PETbuna göre güncelleme yapmanız gerekir . Diğer numaralandırma sistemlerine yeni bir giriş eklemek daha zor ve buggy olabilir.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

𝗘𝘅𝘁𝗲𝗻𝗱 𝗨𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲 𝗩𝗮𝗿𝗶𝗮𝗯𝗹𝗲𝘀 𝗪𝗶𝘁𝗵 𝗔𝗱𝗱𝗶𝘁𝗶𝗼𝗻

Ek olarak, bu numaralandırma sözdizimi, aşağıda görüldüğü gibi açık ve özlü sınıf genişlemesine olanak tanır. Bir sınıfı genişletmek için LEN_, üst sınıfın girişine artan bir sayı ekleyin . Ardından, alt LEN_sınıfın ileride genişletilebilmesi için alt sınıfı kendi girişiyle bitirin .

Ek uzatma diyagramı

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

(Uzunluk: 2.450 bayt)

Bazıları bunun diğer çözümlerden daha az pratik olduğunu söyleyebilir: tonlarca alandan feragat eder, yazmak uzun zaman alır ve şeker sözdizimi ile kaplanmaz. Bu insanlar kodlarını küçültmezlerse haklı olurlar. Bununla birlikte, hiçbir makul kişi nihai üründe minimum kod bırakmaz. Bu minimizasyon için, Closure Compiler henüz bulabildiğim en iyisi. Çevrimiçi erişim burada bulunabilir . Kapatma derleyici tüm bu numaralandırma verilerini almak ve satır içi, böylece Javascript süper küçük süper ve süper süper süper çalıştırmak yapabilirsiniz. Böylece, Kapatma Derleyici ile Küçült. Gözlemek.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

𝗠𝗶𝗻𝗶𝗳𝘆 𝗪𝗶𝘁𝗵 𝗖𝗹𝗼𝘀𝘂𝗿𝗲 𝗖𝗼𝗺𝗽𝗶𝗹𝗲𝗿

Kapatma derleyicisi, diğer herhangi bir Javascript minifier'ın kapasitesinin çok ötesinde olan çıkarımlar yoluyla oldukça inanılmaz bazı optimizasyonlar gerçekleştirebilir. Kapatma Derleyici sabit bir değere ayarlanmış ilkel değişkenleri satır içi yapabilmektedir. Closure Derleyici ayrıca bu satır içi değerlere dayalı çıkarımlar yapabilir ve if ifadeleri ve döngülerdeki kullanılmayan blokları ortadan kaldırabilir.

Closure Compiler ile kodlama

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

(Uzunluk: 605 bayt)

Closure Compiler, daha akıllı kodlama ve kodunuzu iyi organize etmeniz için sizi ödüllendirir, çünkü birçok minimizer organize kodu daha büyük küçültülmüş dosya boyutuyla cezalandırırken, Closure Compiler, hileler kullanırsanız daha küçük bir dosya boyutu elde etmek için tüm temizlik ve akıl sağlığınızı gözden geçirebilir değişken ad numaralandırmaları gibi. Bu, bir akılda, kodlamanın kutsal kâsesi: hem kodunuza daha küçük boyutta yardımcı olan hem de daha iyi programlama alışkanlıkları geliştirerek zihninize yardımcı olan bir araç.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

𝗦𝗺𝗮𝗹𝗹𝗲𝗿 𝗖𝗼𝗱𝗲 𝗦𝗶𝘇𝗲

Şimdi, bu numaralandırmalardan herhangi biri olmadan eşdeğer dosyanın ne kadar büyük olacağını görelim.

Numaralandırma Kullanmadan Kaynak (uzunluk: 1.973 bayt (numaralandırılmış koddan 477 bayt daha kısa!))
Numaralandırma Kullanmadan Küçültülmüş (uzunluk: 843 bayt ( numaralandırılmış koddan 238 bayt daha uzun ))

Kod boyutları tablosu



Görüldüğü gibi, numaralandırma olmadan, kaynak kodu daha büyük bir küçültülmüş kodun maliyetiyle daha kısadır. Seni tanımıyorum; ancak kaynak kodun son ürüne eklenmediğinden eminim. Bu nedenle, bu numaralandırma biçimi, dosya boyutlarının küçültülmesiyle sonuçlanamayacak kadar üstündür.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

𝗖𝗼𝗼𝗽𝗲𝗿𝗮𝘁𝗶𝘃𝗲 🤝 𝗕𝘂𝗴 𝗙𝗶𝘅𝗶𝗻𝗴

Bu numaralandırma formunun bir diğer avantajı, küçültülmüş kod boyutundan ödün vermeden büyük ölçekli projeleri kolayca yönetmek için kullanılabilmesidir. Çok sayıda başka insanla birlikte büyük bir proje üzerinde çalışırken, kodu oluşturan kişi ile değişken adlarını açıkça işaretlemek ve etiketlemek yararlı olabilir, böylece kodun orijinal yaratıcısı işbirlikçi hata düzeltmesi için hızlı bir şekilde tanımlanabilir.

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

𝗦𝘂𝗽𝗲𝗿𝗶𝗼𝗿 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲

Ayrıca, bu numaralandırma şekli minyatürden sonra çok daha hızlıdır. Normal adlandırılmış özelliklerde, tarayıcının özelliğin nesnenin neresinde olduğunu aramak için hashmaps kullanması gerekir. JIT derleyicileri bu konumu nesnede akıllı bir şekilde önbelleğe alsa da, nesneden daha düşük bir özelliği silme gibi özel durumlar nedeniyle hala muazzam bir yük var.

Ancak, sürekli seyrek olmayan tamsayı dizinli PACKED_ELEMENTS dizileriyle, dahili dizideki değerin dizini zaten belirtildiğinden tarayıcı bu ek yükün çoğunu atlayabilir. Evet, ECMAScript standardına göre, tüm özelliklerin dize olarak ele alınması gerekir. Bununla birlikte, tüm tarayıcıların dizilerdeki sayısal dizinler için özel optimizasyonları olduğundan, ECMAScript standardının bu yönü performans konusunda çok yanıltıcıdır.

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

Yukarıdaki kodu aşağıdaki kodla karşılaştırın.

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

Bir numaralandırma sıradan nesneleri ile kod çok daha uzun gibi görünüyor, ama görünüm aldatıcı olabilir. Destansı Closure Compiler kullanırken kaynak kodu boyutunun çıktı boyutuyla orantılı olmadığını hatırlamak önemlidir. Gözlemek.

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

Numaralandırma olmadan küçültülmüş kod yukarıda ve numaralandırmalı küçültülmüş kod aşağıdadır.

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

Yukarıdaki örnek, üstün performansa ek olarak, numaralandırılmış kodun daha küçük boyutta küçültülmüş bir dosya boyutu ile sonuçlandığını göstermektedir.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

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

Ayrıca, üstteki kişisel kiraz, Javascript modunda CodeMirror metin editörü ile birlikte bu numaralandırma formunu kullanıyor . CodeMirror'ın Javascript sözdizimi vurgulama modu, geçerli kapsamdaki yerel değişkenleri vurgular. Bu şekilde, değişken adını doğru yazdığınızda anında bilirsiniz, çünkü değişken adı daha öncevar anahtar , değişken adı özel bir renge döner (varsayılan olarak siyan). CodeMirror kullanmasanız bile, en azından tarayıcı yardımcı olur[variable name] is not definedyanlış numaralandırma adlarıyla kod yürütülürken kural dışı durum. Ayrıca, JSLint ve Closure Compiler gibi JavaScript araçları, bir numaralandırma değişkeni adına yanlış yazdığınızı size söyleme konusunda çok gürültülüdür. CodeMirror, tarayıcı ve çeşitli Javascript araçları, bu numaralandırmada hata ayıklamayı çok basit ve gerçekten kolay hale getirir.

CodeMirror vurgulama gösterisi

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
}

Yukarıdaki snippet'te, var olmadığı için bir hata ile uyarıldınız ENUM_COLORENUM_DNE.


wvwwvw wvwvwvw wvwxvw wvwvwv vwvwvw wvwvvw wvwvvv

𝗖𝗼𝗻𝗰𝗹𝘂𝘀𝗶𝗼𝗻 ☑

Bu numaralandırma yönteminin gerçekten sadece küçültülmüş kod boyutu için değil, aynı zamanda performans, hata ayıklama ve işbirliği için de en iyi yol olduğunu söylemek güvenli olduğunu düşünüyorum.

Yararlı bir soru okuduktan sonra, yazarın soru kutusuna sol üst yukarı oku tıklayarak yazılarına zaman ayırdığı için teşekkür ederim. Her yanıt kutusunda bu yukarı oklardan biri bulunur.


Eh. Kod büyüklüğünde okunabilirliği, kullanım kolaylığını ve anlayışı kesinlikle tercih ediyorum.
Andrew

1
@Andrew Cevabımla her ikisine de sahip olabilirsiniz. Cevabım, kodu kullanmanın / yönetmenin en kolayı ve küçültülmüş en küçük kod boyutuyla sonuçlanır.🙂
Jack Giffin

1
@Andrew Cevabımdaki renk ayrıştırıcı örneğine Yet Another Enum'unuzu (YEA!) Uygulamaya çalıştım. Ancak, ele almak isteyebileceğiniz birkaç sorun buldum. YEA'nın alt sınıflarla sayımları genişletmesi mümkün değil, bu da beni büyük projelerde yönetilmesi oldukça zor olabilecek ayrı ebeveyn ve çocuk sınıfları oluşturmaya zorluyor. YEA , girişin var olmasını garanti etmez (eski colors.REEDgetiriler undefined), bu nedenle yazım hataları zor anlaşmalar yaratır. YEA , numaralandırmaların dizinler ve kimlikler olarak kullanımı arasında ayrım yapmaz ve her şeyin aynı göründüğü kafa karıştırıcı kodlara yol açar. …
Jack Giffin

1
@Andrew… YEA, Closure Compiler'ın küçültme yeteneğini engelliyor. Kaynak kodunu YEA (3549 bayt) ile küçültülmüş kodu YEA (1344 bayt) ile küçültülmüş kodu çözümümle (604 bayt) karşılaştırın. Son olarak, YEA dize adlarını numaralandırılmış kimliklerden ayırdığı için "ada göre eşleme" yi içerir. Benimki sadece kimliği düşünür, bu nedenle daha basit bir tasarıma ve daha iyi performansa yol açan "ada göre eşleme" gerekmez. Çözümünüzü paylaştığınız için teşekkür ederiz, ancak pratik olabilmesi için birçok düzeltmeye ihtiyacı vardır.
Jack Giffin

1
@Andrew Ben benim olduğum için görüşüne hakkınız var 👍
Jack Giffin

23

Enums'ımı sevdiğim için bununla oynuyorum. =)

Kullanılması Object.definePropertyBen biraz yaşayabilir çözüm geldi düşünüyorum.

İşte bir jsfiddle: http://jsfiddle.net/ZV4A6/

Bu yöntemi kullanarak .. (teoride) o nesnenin diğer niteliklerini etkilemeden herhangi bir nesne için numaralandırma değerlerini çağırabilir ve tanımlayabilirsiniz.

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

Çünkü özelliğinin writable:falsebu olmalıdır güvenli yazın olun.

Bu nedenle, özel bir nesne oluşturabilmeniz ve sonra Enum()onu çağırabilmeniz gerekir. Atanan değerler 0 ile başlar ve öğe başına artıştır.

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3

3
return this;Enum'un sonuna eklerseniz şunları yapabilirsiniz:var EnumColors = {}.Enum('RED','BLUE','GREEN','YELLOW');
HBP

Normal bir şeyler yapma yöntemim olmadığı için bunu düşünmedim. Ama kesinlikle haklısın! Bunu düzenleyeceğim.
Duncan

Nesne alanı (küresel işlevi ENUM ile) kadar mucking büyük bir hayranı olmasam da bunu gerçekten seviyorum. Bunu bir mkenum işlevine dönüştürdü ve isteğe bağlı sayısal atamalar ekledi => var mixedUp = mkenum ('BLACK', {RED: 0x0F00, BLUE: 0X0F, YEŞİL: 0x0F0, BEYAZ: 0x0FFF, ONE: 1}, İKİ, ÜÇ, DÖRT) ; // Kodumu aşağıda cevap olarak ekliyorum. Teşekkürler.
Andrew Philips

Dürüst olmak gerekirse, artık bunu kullanmıyorum. Google'ın Closure Compiler'ı kullanıyorum ve Gelişmiş ayarını kullanırsanız bu çok iyi çalışmaz (veya yalnızca işleri karmaşık hale getirir). Bu yüzden standart nesne gösterimine geri döndüm.
Duncan

1
falseiçin varsayılan değerdir writable, enumerableve configurable. Varsayılanlar üzerinde çiğnemeye gerek yok.
ceving

23

Javascript Proxy'leri Kullanma

TLDR: Bu sınıfı yardımcı program yöntemlerinize ekleyin ve kodunuz boyunca kullanın, geleneksel programlama dillerinden Enum davranışını atar ve var olmayan bir numaralandırıcıya erişmeye çalıştığınızda veya numaralandırıcı eklerken / güncellerken hatalar atar. Güvenmeye gerek yok 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);
  }
}

Daha sonra sınıfı başlatarak numaralandırmalar oluşturun:

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

Tam Açıklama:

Geleneksel dillerden aldığınız Enum'ların çok yararlı bir özelliği, mevcut olmayan bir numaralandırıcıya erişmeye çalıştığınızda havaya uçmasıdır (derleme zamanı hatası verir).

Ek değerlerin yanlışlıkla / kötü amaçlı olarak eklenmesini önlemek için alay konusu numaralandırma yapısının dondurulmasının yanı sıra, diğer yanıtların hiçbiri Enum'un kendine özgü özelliğini ele almaz.

Muhtemelen bildiğiniz gibi, JavaScript'te mevcut olmayan üyelere erişmek sadece undefined ve kodunuzu patlatmaz. Sayıcılar önceden tanımlanmış sabitler (yani haftanın günleri) olduğundan, bir sayıcının tanımlanmaması gereken bir durum olmamalıdır.

Beni yanlış anlamayın, JavaScript'in geri dönme davranışı undefined tanımlanmamış özelliklere erişirken aslında dilin çok güçlü bir özelliğidir, ancak geleneksel Enum yapılarını taklit etmeye çalıştığınızda istediğiniz bir özellik değildir.

Proxy nesnelerinin parladığı yer burasıdır. Proxy'ler, ES6 (ES2015) uygulamasıyla birlikte dilde standartlaştırıldı. İşte MDN'den açıklama:

Proxy nesnesi, temel işlemler (örneğin özellik arama, atama, numaralandırma, işlev çağırma, vb.) İçin özel davranışı tanımlamak için kullanılır.

Bir web sunucusu proxy'sine benzer şekilde, JavaScript proxy'leri nesneler üzerindeki işlemleri kesebilir ("tuzaklar" kullanarak, isterseniz kancaları çağırabilir) ve tamamlanmadan önce çeşitli denetimler, eylemler ve / veya manipülasyonlar gerçekleştirmenize izin verir (veya bazı durumlarda operasyonları tamamen durdurma. Bu, mevcut olmayan bir numaralandırıcıya başvurmaya çalıştığımızda ve ne zaman yapmaya çalıştığımızdır.

İşte Enum'ları taklit etmek için Proxy nesnesini kullanan bir örnek. Bu örnekteki numaralandırıcılar standart HTTP Yöntemleridir (yani "GET", "POST" vb.):

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


ASIDE: Vekil sunucu nedir?

Proxy kelimesini her yerde görmeye başladığımda hatırlıyorum, kesinlikle uzun bir süre bana mantıklı gelmedi. Şu anda sizseniz, proxy'leri genelleştirmenin kolay bir yolunun bunları yazılım, kurum veya hatta iki sunucu, şirket veya insan arasında aracı veya aracı olarak hareket eden insanlar olarak düşünmek olduğunu düşünüyorum.


MyEnum.valueOf ("someStringValue") gibi bir şey nasıl yapılır? Beklenen: giriş dizgisinin numaralandırıcı öğesinin bir değerine sahip olması durumunda öğeyi döndürmelidir. Hiçbir öğenin dize değerine sahip olmaması durumunda, istisna atın.
sscarduzio

@sscarduzio valueOf, Enum sınıfında örnek yöntem olarak belirterek varsayılan yöntemi geçersiz kılabilirsiniz . Ancak, neden sadece nokta gösterimi ile erişmeye karşı bu şekilde erişmek istiyorsunuz?
Govind Rai

Benim numaralandırma const logLevelEnum = new Enum ({INFO: "info", DEBUG: "debug"}) ve ben rasgele bir dize "info" veya "debug" girdi ayrıştırmak. Yani currentLogLevel = logLevelEnum.parseOrThrow (settings.get ("
log_level

1
Neden sadece yapamadın logLevelEnum[settings.get("log_level")]? ekleme işlemi parseOrThrow, proxy tuzaklarının sizin için halihazırda yaptıklarını tekrarlar.
Govind Rai

17

Bu bildiğim eski bir yöntem, ancak o zamandan beri TypeScript arabirimi aracılığıyla uygulanma şekli:

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

Bu, bildirim sırasına bakılmaksızın MyEnum.Bar, hem 1 döndüren hem de MyEnum[1]"Bar" döndüren aramaları yapmanızı sağlar .


1
Artı MyEnum ["Bar"] şu ana kadar 1 ... <3 TypeScript döndüren işler ...
David Karlaš

3
ve tabii ki eğer gerçekten daktilo kullanıyorsanız:enum MyEnum { Foo, Bar, Foobar }
parlamento

16

In ES7 , statik niteliklerini güvenerek zarif enum yapabilirsiniz:

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

sonra

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

Avantajı (değişmez nesne yerine sınıf kullanmanın) bir üst sınıfa sahip olması, Enumtüm Numaralandırmalarınız bu sınıfı genişletir .

 class ColorEnum  extends Enum {/*....*/}

4
Ebeveyn sınıfına sahip olmanın neden bir avantaj olduğunu açıklar mısınız? Bir şeyleri özlediğimi hissediyorum!
Jon G

7
Bunu yapma. new ColorEnum()hiçbir anlam ifade etmiyor.
Bergi

3
bir enum genişletmek gerçekten çılgınca geliyor
Codii

dil bu dili desteklemediğinde bu konvansiyonu korumak ve böyle kullanmak mantıklı olur! Katılıyorum!
xpto

Bence (?) OP'nin elde ettiği şey: Saf statikin yararı, her yerde tekil olarak kullanılabilmesidir ve sınıfı somutlaştırmanıza gerek yoktur - OP bunu yapmanızı önermez! Ne demek istediğini üst sınıf olduğunu düşünüyorum Enumstandart vardır statik üzerinde Numaralayıcı yöntemleri gibi getValues(), getNames(), iterate()Eğer durum buysa, vs, her yeni tür için onları tekrar uygulamanız gerekmez enum.
Mühendis

15

Kullandığım çözüm bu.

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

Ve numaralarınızı şöyle tanımlarsınız:

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

Ve numaralarınıza şu şekilde erişirsiniz:

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

Genellikle ileti nesnelerinden gelen numaralandırmaların eşleştirilmesi için son 2 yöntemi kullanırım.

Bu yaklaşımın bazı avantajları:

  • Numaralandırma bildirimi kolay
  • Numaralarınıza kolay erişim
  • Numaralarınız karmaşık türler olabilir
  • GetByValue çok kullanıyorsanız Enum sınıfının bazı ilişkilendirilebilir önbelleği vardır

Bazı dezavantajları:

  • Bazı dağınık bellek yönetimi orada devam ediyor, ben enum referanslarını tutarken
  • Hala güvenlik yok

14

Değişmez nesne oluşturma:

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

12
constnesnenin özelliklerini değişmez kılmaz, yalnızca değişkenin Modesbaşka bir şeye yeniden atanamayacağı anlamına gelir . Daha eksiksiz hale getirmek için Object.freeze()birlikte kullanın const.
rvighne

Lütfen kullanmayın Object.freeze. Closure Derleyici'nin nesneyi satır içine almasını engeller.
Jack Giffin

11

Eğer kullanıyorsanız Omurga , sen tam gelişmiş enum işlevsellik olsun ücretsiz kullanmak için (id, ad, özel üyeleri tarafından bulmak) olabilir 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()

8

cevaplarınız çok karmaşık

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

1
@JackGiffin Cevabınızın daha performanslı olduğunu ve benimkinin daha fazla bellek alabileceğini kabul ediyorum, ancak herkesin C ++ uygulamasının uyguladığı şekilde bir numaralandırma istediğini varsaymamalısınız. Lütfen diğer yanıtlara ve bunu sizin tercihinize göre tercih edebilecek geliştiricilere saygı gösterin.
Xeltor

7

Andre 'Fi'nin çözümünü değiştirdim:

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

Ölçek:

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

6

Java'daki numaralandırmalardan sonra modellenen bu yaklaşımı buldum . Bunlar tip güvenlidir ve böyleceinstanceof denetimler de .

Sekmeleri şu şekilde tanımlayabilirsiniz:

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

Daysşimdi Daysnumaralandırmaya atıfta bulunur :

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"

Hayata geçirme:

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
    }

})();

Güzel görünüyor, belki freezegeriye dönük uyumluluk için yöntemin varlığını kontrol etmelisiniz ? Örneğin,if (Object.freeze) { Object.freeze(values); }
FBB

İyi bir nokta! Yapacağım!
Vivin Paliath

6

IE8, freeze () yöntemini desteklemez.
Kaynak: http://kangax.github.io/compat-table/es5/ , "Eski tarayıcılar gösterilsin mi?" üstte IE8'i kontrol edin ve satır sütun kavşağını dondurun

Mevcut oyun projemde, birkaç müşteri hala IE8 kullandığından aşağıda kullandım:

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

Ayrıca şunları da yapabiliriz:

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

hatta bu:

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

Sonuncusu, dize için en verimli görünüyor, sunucu ve istemcinizin bu verileri alıp vermesi durumunda toplam bant genişliğinizi azaltır.
Tabii ki, şimdi verilerde çakışma olmadığından emin olmak sizin görevinizdir (RE, EX, vb. Benzersiz olmalı, ayrıca 1, 2 vb. Benzersiz olmalıdır). Geriye dönük uyumluluk için bunları sonsuza kadar korumanız gerektiğini unutmayın.

Görev:

var wildType = CONST_WILD_TYPES.REGULAR;

karşılaştırma:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}

5
var ColorEnum = {
    red: {},
    green: {},
    blue: {}
}

Bu şekilde farklı numaralandırma değerlerine yinelenen sayılar atamadığınızdan emin olmanız gerekmez. Yeni bir nesne başlatılır ve tüm numaralandırma değerlerine atanır.


Bu cevabın önemsiz olduğu anlaşılıyor. Sadeliği için en sevdiğim fikirlerden biri. Pratikte, sanırım dizelere yapışacağım çünkü şimdilik hata ayıklamak daha kolay.
Domino

Hmm, bu kodun iki kez çağrılmadığından emin ol ...
Andrew

4

İşte TypeScript numaralandırmalarını uygulamanın birkaç farklı yolu .

En kolay yol, bir nesnenin üzerinde yineleme yapmak ve nesneye ters çevrilmiş anahtar / değer çiftleri eklemektir. Tek dezavantajı, her üye için değeri manuel olarak ayarlamanızdır.

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


Ve işte bir dize kullanarak bir enum oluşturmak için lodash bir mixin . Bu sürüm biraz daha ilgili olsa da, numaralandırmayı sizin için otomatik olarak yapar. Bu örnekte kullanılan tüm lodash yöntemlerinin düzenli bir JavaScript eşdeğeri vardır, böylece isterseniz bunları kolayca kapatabilirsiniz.

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

çok zeki, teşekkürler
Ilan

4

Az önce bir NPM paketi yayınladım gen_enum , Javascript'te hızlı bir şekilde Enum veri yapısı oluşturmanıza izin veriyor:

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 

Bu küçük araç hakkında güzel bir şey, modern ortamda (nodejs ve IE 9+ tarayıcıları dahil) döndürülen Enum nesnesi değişmez.

Daha fazla bilgi için lütfen https://github.com/greenlaw110/enumjs adresini ziyaret edin.

Güncellemeler

Ben eski gen_enumpaketi ve içine fonksiyonu birleştirme constjs sabit nesneler, JSON dize serisini kaldırma, dize sabitleri ve bitmap nesil dahil daha fazla özellikler sağlayan paketin vb Ödeme https://www.npmjs.com/package/constjs fazla bilgi için

Yükseltmek için gen_enumiçin constjssadece deyimi değiştirmek

var genEnum = require('gen_enum');

için

var genEnum = require('constjs').enum;

4

En basit çözüm:

Oluşturmak

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

Değer elde etmek

console.log(Status.Ready) // 1

Anahtarı al

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

4

O (1) de değerleri VE isimlerini getirebilir bir Enum sınıfı yaptım. Ayrıca tüm Adları ve Değerleri içeren bir Nesne Dizisi oluşturabilir.

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

Bunu şu şekilde başlatabilirsiniz:

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

Bir değer getirmek için (C # 'daki Numaralamalar gibi):

var val2 = enum1.item2;

Bir değer için bir ad getirmek için (farklı adlar için aynı değeri girerken belirsiz olabilir):

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

Bir nesnedeki her ad ve değere sahip bir dizi almak için:

var arr = enum1.GetObjArr();

Üretecek:

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

Html seçim seçeneklerini kolayca elde edebilirsiniz:

var html = enum1.GetSelectOptionsHTML();

Hangi tutar:

"<option value='0'>item1</option>..."

4

Olsa sadece statik yöntemler (ve statik özellikleri) (bkz ES2015 desteklenir burada , hem de §15.2.2.2), merakla Birlikte Babel ile aşağıda kullanabilirsiniz es2015önceden:

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

Bunun modüller arasında bile beklendiği gibi çalıştığını gördüm (örn. CellState numaralandırmayı başka bir modülden ) ve Webpack kullanarak bir modülü içe aktardığımda gördüm.

Bu yöntemin diğer yanıtların çoğuna göre avantajı, statik bir tür denetleyicinin (örn. Flow ) yanında kullanabilmeniz ve geliştirme sırasında statik tür denetimini kullanarak değişkenlerinizin, parametrelerinizin vb.CellState " enum "yerine başka bir enum (genel nesneler veya semboller kullandıysanız ayırt etmek imkansızdır) yerine.

Güncelleme

Yukarıdaki kod, bir kişinin ek tür nesneler oluşturmasına izin vermesi bakımından bir eksikliğe sahiptir CellState( CellStatedondurulmuş olduğu için bunları statik alanlara atayamasa da). Yine de, aşağıdaki daha rafine kod aşağıdaki avantajları sunar:

  1. başka türde nesne yok CellState oluşturulamaz
  2. iki enum örneğine aynı kodun atanmadığı garanti edilir
  3. enum bir dize temsilinden geri almak için yardımcı yöntem
  4. valuesenum döner tüm örnekler yukarıdaki kılavuzu (ve hata eğilimli) bir şekilde geri dönüş değeri yaratmak zorunda değildir bu işlevi.

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

İyi örnek :-)
Ashraf.Shk786

4

es7 yolu, (yineleyici, dondurma), kullanım:

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'

kod:

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(', ') }

}

4

Typescript bunu enumJavascript'e çevirir :

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

Şimdi:

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

İlk başta neden obj[1]geri döndüğünü kafam karıştı 'Active', ama sonra onun ölü basit olduğunu fark ettim - Atama operatörü değer atar ve sonra döndürür:

obj['foo'] = 1
// => 1

4

Böyle bir şey yapabilirsin

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

Bu kütüphanede tanımlandığı gibi. https://github.com/webmodule/foo/blob/master/foo.js#L217

Tüm örnek https://gist.github.com/lnt/bb13a2fd63cdb8bce85fd62965a20026


3

Hızlı ve basit bir yol:

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

console.log(Colors.WHITE)  //this prints out "0"

6
İşlev gereksizdir ve OP'nin gönderdiği ile aynı sonucu verir.
Sildoreth

3

Yazılı olarak, Ekim 2014 - işte burada çağdaş bir çözüm. Çözümü bir Düğüm Modülü olarak yazıyorum ve Mocha ve Chai'nin yanı sıra alt çizgi JS kullanarak bir test ekledim. Bunları kolayca yok sayabilir ve tercih ederseniz Numaralandırma kodunu girebilirsiniz.

Aşırı kıvrık kütüphaneler vb. İle bir sürü mesaj gördüm. Javascript'te enum desteği almanın çözümü gerçekten gerekli olmayan kadar basit. İşte kod:

Dosya: 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;

Ve size ne verdiğini gösteren bir test:

dosya: 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');
        });
    });

});

Gördüğünüz gibi, bir Enum fabrikası elde edersiniz, enum.keys'i çağırarak tüm anahtarları alabilirsiniz ve anahtarları kendileri tamsayı sabitleriyle eşleştirebilirsiniz. Ayrıca fabrikayı farklı değerlerle tekrar kullanabilir ve üretilen bu Numaraları Düğümün modüler yaklaşımını kullanarak dışa aktarabilirsiniz.

Bir kez daha, sadece sıradan bir kullanıcıysanız veya tarayıcı vb. İseniz, kodun fabrika kısmını alın ve kodunuzda kullanmak istemiyorsanız alt çizgi kitaplığını da kaldırın.


5
Sadece "bunu fabrikalar, alt çizgiler veya süslü bir şey değil, yalnızca numaralandırma isteyen sıradan bir kullanıcı olarak nasıl yapacağınız" ile yanıt gönderebilir misiniz?
GreenAsJade

5
Bu, geliştiricilerin bakış açısından oldukça harika olsa da, çok temiz veya okunabilir değil. OP'nin Enum çözümü her yönden daha kolay ve daha okunabilir ve bu nedenle kullanımı daha iyidir. Yine de, bunu bulduğunuzda hayret verici.
David

3

Bence kullanımı kolay. 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);

GÜNCELLEME:

Yardımcı kodlarım ( TypeHelper) var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.