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


JavaScript'te enumları 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ı?


1678
2017-11-13 19:09


Menşei


Odesk üzerinde Javascript 1.8'de bir test yapıyordum ve javascript'te sayımı çözmek için ne gerekiyor diye sordular, 2 açık cevaplar ya anahtar kelime veya jeneratörlerdi. C ++ kursumdaki enumları hatırlıyorum ve jeneratörler ne olduğunu gerçekten bilmiyorum; ama potansiyel olarak bu yardımcı olur. - Devin G Rhode
Kullanma 0 bir numaralama numarası olarak. Ayarlanmamış bir şey için kullanılmadıkça. JS davranır false || undefined || null || 0 || "" || '' || NaNtüm karşılaştırılan ile karşılaştırıldığında aynı değer ==. - matsko
@matsko == kullanarak bir argüman değil mi? - sdm350
Fakat false == 0 ve +null == 0 (ve beklemediğinizde sayılara dönüşümler bazen gerçekleşir) null == undefined ve +undefined olduğu NaN (gerçi NaN != NaN). - sanderd17
Çift eşitlik matrisi, microsoft word'ün otomatik biçimlendirmesinden daha kafa karıştırıcıdır - aaaaaa


Cevaplar:


1.8.5'ten beri nesneyi mühürlemek ve dondurmak mümkündür, böylece yukarıdakileri tanımlayın:

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

veya

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

ve voila! JS enums.

Bununla birlikte, bu, genellikle enumları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 tipte güvenlik sağlamak için bir yol (enumlar ile veya başka şekilde) gibi bir araç kullanmaktır daktilo ile yazılmış yazı veya Akış.

Kaynak

Tırnaklar gerekli değil ama onları tutarlılık için sakladım.


541
2018-02-18 11:03



Wikipedia'ya göre (en.wikipedia.org/wiki/JavaScript#Versions) Firefox 4, IE 9, Opera 11.60’a uygulanabilir ve Chrome’da çalıştığını biliyorum. - Artur Czajka
Bu 2012 yılında doğru cevaptır. Daha basit: var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });. Bir kimlik belirtmeniz gerekmez, enumları karşılaştırmak için boş bir nesneyi kullanabilirsiniz. if (incommingEnum === DaysEnum.monday) //incommingEnum is monday - Gabriel Llamas
Geriye dönük uyumluluk için, if (Object.freeze) { Object.freeze(DaysEnum); } - saluce
Bunu yapmak isterim ({ monday: {},  vb. Eğer nesneyi stringona ile JSON'a çevirirseniz [{"day": {}}] Bu işe yaramayacak. - jcollum
@Supuhstar Bu soru hakkındaki görüşüm artık farklı. Freeze () kullanmayın, tamamen işe yaramaz ve "aptal" şeyler yapmak için zaman kaybıdır. Bir enum açıklamak istiyorsanız, bunu basitçe açığa çıkarın: var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}. Önceki yorumumdaki gibi nesneleri karşılaştırmak, sayıları karşılaştırmaktan çok ÇOK DAHA ÇOK. - Gabriel Llamas


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

Bunu söylemiş olursak, değerlerin ne olduğu önemli değil (0, 1, 2 kullandınız), şimdiki değeri almak istediğinizde anlamlı bir ip kullanırdım.


583
2017-11-13 19:13



İşte yarattığım basit bir enum fabrikası; npmjs.org/package/simple-enum - Tolga E
Üzgünüz, ancak bu enum uygulamasının çeşitli sorunları var. Bunun yerine şunu kullanmanızı öneriyorum: github.com/rauschma/enums - paldepind
Bu başka bir cevapta belirtildi, ancak bu cevap kabul edilen cevap olduğundan, bunu burada yayınlayacağım. OP'nin çözümü doğru. Bununla birlikte, daha da iyi olacak Object.freeze(). Bu, diğer kodun enum'un değerlerini değiştirmesini engeller. Örnek: var ColorEnum = Object.freeze({RED: 0, GREEN: 1, BLUE: 2}); - Sildoreth
@TolgaE bu kütüphane için teşekkürler! Bu beni sadece en düşük değere kadar kaynatmak için değil, aynı zamanda birkaç özellik katmak için bana ilham verdi! Ben seninkini çatallandırdım ve hepsini buraya koy. github.com/BlueHuskyStudios/Micro-JS-Enum - Supuhstar
@Supuhstar Bu harika! Kullanabileceğine sevindim .. Eğer bu kütüphanede birleştirilmesini istediysen bir çekme talebi yapmaktan çekinme, npm kütüphanesini güncelleyebilirim. - Tolga E


GÜNCELLEŞTİRME: Herkes için tüm oylar için teşekkürler, ama aşağıda cevabım Javascript içinde enum yazmak için en iyi yol olduğunu düşünmüyorum. Daha fazla ayrıntı için blog gönderime bakın: Javascript'teki Enumlar.


İsmi bildirmek zaten mümkün:

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 yapabilirsiniz, böylece pastayı alabilir ve 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ğu için, enum değerlerini daha sonra kümeye eklemek bile mümkündür:

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

Unutmayın, enumun alanları (bu örnekteki değer, isim ve kod) kimlik kontrolü için gerekli değildir ve sadece kolaylık için vardır. Ayrıca, boyut özelliğinin adının kodlanmış olması gerekmez, ancak dinamik olarak da ayarlanabilir. Dolayısıyla, yalnızca yeni enum değerinizin adını bildiğinizi varsayarak, sorunsuz olarak ekleyebilirsiniz:

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

Elbette bu, bazı varsayımların artık yapılamayacağı anlamına gelir (bu değer, örneğin boyut için doğru sırayı gösterir).

Unutmayın, Javascript'te bir nesne tıpkı bir harita veya karmaşa gibidir. İsim-değer çiftleri kümesi. Onlardan geçebilir veya önceden onlar hakkında fazla bilgi sahibi olmadan bunları manipüle edebilirsiniz.

ÖRNEĞİN:

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

Ve btw, ad alanlarıyla ilgileniyorsanız, javascript için basit ama güçlü ad alanı ve bağımlılık yönetimi çözümüme bir göz atmak isteyebilirsiniz: Paketler JS


477
2018-03-04 22:31



Öyleyse, sadece ismine sahip olursanız nasıl bir SIZE oluşturabilirdiniz? - Johanisma
@Johanisma: Bu kullanım durumu, tüm fikirleri önceden bildiğiniz gibi, enumlar için mantıklı değildir. Ancak, daha sonra Javascript'te ekstra değerler eklemekten sizi durduran hiçbir şey yoktur. Buna cevabımın bir örneğini ekleyeceğim. - Stijn de Witt
Çok iyi cevap verdi. İhtiyaç duyulduğunda JS / JQ'nun sıradan bir kullanıcısıyım ve bu da SharePoint ile çözülmesi gereken bir duruma yardımcı oldu. - GoldBishop
Özellikler yaklaşımına sahip yayınınıza bağlantı için +1. Zarif, basit deklarasyonlar, OP'de olduğu gibi, arzu edildiğinde eklenen özellikler özelliği ile basittir. - goodeye
@DavideAndrea Haklısınız. Blogumu kendi alan adıma göre kullanmaya başladım. Bağlantı güncellendi. Bahsettiğin için teşekkürler! - Stijn de Witt


Alt satır: Yapamazsın.

Taklit edebilirsin ama tip güvenliği olmaz. Tipik olarak bu, tamsayı değerlerine eşlenen dize değerleri basit bir sözlük oluşturarak yapılır. Örneğin:

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

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

Bu yaklaşımdaki problem? Sayınızı yanlışlıkla yeniden tanımlayabilir veya yanlışlıkla yinelenen sayım değerlerine sahip olabilirsiniz. Örneğin:

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

Düzenle 

Artur Czajka'nın Object.freeze'den ne haber? Pazartesiden perşembeye gitmenizi engellemek için işe yaramaz mı? - Fry Quad

Kesinlikle, Object.freeze şikayet ettiğim sorunu tamamen düzeltirdi. Herkesi hatırlattığımda herkese hatırlatmak isterim. Object.freeze gerçekten yoktu.

Şimdi .... şimdi biraz açılıyor çok ilginç olanaklar.

2'yi düzenle
İşte enumlar oluşturmak için çok iyi bir kütüphane.

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

Her türlü geçerli enumat kullanımına uymuyor olsa da, çok uzun bir yol kat ediyor.


79
2017-08-21 20:56



Javascript'te güvenlik var mı? - Scott Evernden
Bu yüzden değerleri nesne özelliklerine göre eşleştirmeyin. Numaralandırıcıya erişmek için getter kullanın ("private" nesnesinin bir özelliği olarak saklanır). Saf bir uygulama şöyle görünecekti - var daysEnum = (function(){ var daysEnum = { monday: 1, tuesday: 2 }; return { get: function(value){ return daysEnum[value]; } } })(); daysEnum.get('monday'); // 1 - kangax
@ Everstock: nokta alındı. @kangax: nokta şu ki hala bir hack. Enumlar sadece Javascript, dönem, hikayenin sonu içinde mevcut değildir. Tim Sylvester tarafından önerilen desen bile hala ideal bir hack. - Randolpho
Kodun hazır bilgi ile karıştırılması, çok bakım gerektirmez, bu yüzden sabitler oluşturmak anlamlıdır. Elbette Javascript'in de sabitleri yoktur. Yani temelde bu sadece temiz kod yazmanın bir yoludur. Zorlanamaz, ama Javascript'te fazla bir şey olamaz. Sabitleri veya işlevleri veya çoğu şeyi yeniden tanımlayabilirsiniz. EG: document.getElementById = function () {alert ("Siz hapsoldunuz. Javascript typesafe değil.");}; - Stijn de Witt
@Randolpho: Peki ya Artur Czajka'nın Object.freeze? Pazartesiden perşembeye gitmenizi engellemek için işe yaramaz mı? - Michael


Hepimizin istediği:

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

Şimdi enumlarınızı yaratabilirsiniz:

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

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

Enum.prototype'ı kullanarak da yöntemler 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üzenle - küçük iyileştirme - şimdi varargs ile: (maalesef IE'de düzgün çalışmıyor: S ... daha önceki versiyona bağlı kalmalı)

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
2017-07-13 00:28





Çoğu modern tarayıcıda, bir sembol Bir numaralandırma oluşturmak için kullanılabilecek ilkel veri türü. Her sembol değerinin JavaScript tarafından benzersiz olması garantili olduğundan, enumun tip güvenliğini sağlayacaktır, örn. Symbol() != Symbol(). Örneğin:

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

Hata ayıklamayı basitleştirmek için enum değerlerine bir açıklama ekleyebilirsiniz:

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

Plunker demosu

üzerinde GitHub numarayı başlatmak için gereken kodu basitleştiren bir sarı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

41
2018-05-05 16:32



Teoride doğru cevap budur. Uygulamada, 2015 tarayıcı desteği yeterli olmaktan uzaktır. Üretim bugüne kadar hazır değil. - vbraun
Henüz tarayıcı desteği olmasa da, bu en iyi cevaptır, Symbol Için tasarlanmıştır. - rvighne
Meh ... enum değerlerinin sık sık seri hale getirilmesi gerekir ve Semboller serileştirmek ve serileştirmek için çok kullanışlı değildir. - Andy


Benimle oynadım, enumlarımı seviyorum. =)

kullanma Object.defineProperty Sanırım biraz uygulanabilir bir çözüm buldum.

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

Bu yöntemi kullanarak .. (teoride), o nesnenin diğer özelliklerini etkilemeden, herhangi bir nesne için enum değerlerini çağırıp tanımlayabilmelisiniz.

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

Özellik nedeniyle writable:false bu meli güvenli yazın.

Yani özel bir nesne oluşturabilirsin, sonra ara Enum() üstünde. Atanan değerler 0'da başlar ve öğe başına artış.

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

23
2017-08-21 10:34



Eklerseniz return this; Enum'un sonunda şunları yapabilirsiniz: var EnumColors = {}.Enum('RED','BLUE','GREEN','YELLOW'); - HBP
Bunu yapmadım, çünkü normal şeyler yapma yöntemim değil. Ama kesinlikle haklısın! Bunu düzenlerim. - Duncan
Bunu gerçekten beğendim, ancak Object space'i (ENUM global işleviyle) birleştirmek için büyük bir hayranı değilim. Bunu bir mkenum işlevine dönüştürdü ve isteğe bağlı sayısal atamaları ekledi => var mixedUp = mkenum ('SİYAH', {KIRMIZI: 0x0F00, MAVİ: 0X0F, YEŞİL: 0x0F0, BEYAZ: 0x0FFF, BİR: 1}, İKİ, ÜÇ, DÖRT) ; // Kodumu aşağıdaki yanıt olarak ekliyorum. Teşekkürler. - Andrew Philips
Dürüst olmak gerekirse, bunu artık kullanmıyorum. Google'ın Closure Compiler'ı kullanıyorum ve Gelişmiş ayarını kullanırsanız bu çok işe yaramıyor (ya da sadece işleri zorlaştırıyor). Bu yüzden standart nesne notasyonuna geri döndüm. - Duncan
false için varsayılan writable, enumerable ve configurable. Varsayılanlar üzerinde çiğnemeye gerek yok. - ceving


Bu bildiğim eski bir şey, ama o zamandan beri TypeScript arabirimiyle uygulanan yol:

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

Bu, her ikisine de bakmanızı sağlar MyEnum.Bar 1 döndürür ve MyEnum[1] beyan sırasına bakılmaksızın "Bar" döndürür.


17
2018-06-24 16:11



Artı MyEnum ["Bar"], şu ana kadar 1 ... <3 TypeScript döndüren çalışır ... - David Karlaš
ve tabiki gerçekten de Typescript'i kullanıyor iseniz: enum MyEnum { Foo, Bar, Foobar } - parliament


Bu benim kullandığım çözüm.

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 envanterinizi şöyle tanımlarsınız:

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

Ve bu sizin enumlarınıza nasıl erişeceğiniz:

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 enonları mesaj nesnelerinden eşlemek için son 2 yöntemi kullanırım.

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

  • Envanteri beyan etmek kolay
  • Enumlarınıza kolayca erişin
  • Enemleriniz karmaşık tipler olabilir
  • Enum sınıfı, getByValue'yi çok kullanırsanız bazı ilişkilendirilebilir önbelleğe alma özelliğine sahiptir.

Bazı dezavantajları:

  • Bazı karışık bellek yönetimi oraya gidiyor,
  • Hala güvenlik yok

15
2018-05-15 09:26