Domanda Qual è la sintassi preferita per definire le enumerazioni in JavaScript?


Qual è la sintassi preferita per definire le enumerazioni in JavaScript? Qualcosa di simile a:

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

// later on

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

O c'è un idioma più preferibile?


1674
2017-11-13 19:09


origine


risposte:


Dal 1.8.5 è possibile sigillare e congelare l'oggetto, quindi definire quanto sopra come:

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

o

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

e voilà! JS enums.

Tuttavia, ciò non impedisce di assegnare un valore indesiderato a una variabile, che è spesso l'obiettivo principale dell'enumerazione:

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

Un modo per garantire un livello più elevato di sicurezza del tipo (con enumerazioni o altro) è usare uno strumento come Dattiloscritto o Flusso.

fonte

Le quotazioni non sono necessarie ma le ho mantenute per coerenza.


539
2018-02-18 11:03



Questa non è una grande risposta, ma direi che funziona perfettamente, personalmente

Detto questo, dato che non importa quali sono i valori (hai usato 0, 1, 2), userei una stringa significativa nel caso tu abbia mai voluto emettere il valore corrente.


583
2017-11-13 19:13



AGGIORNARE: Grazie per tutti gli upvotes di tutti, ma non credo che la mia risposta qui sotto sia il modo migliore per scrivere enum in Javascript più. Vedi il mio post sul blog per ulteriori dettagli: Enum in Javascript.


Avvisare il nome è già possibile:

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

In alternativa, puoi rendere i valori oggetti, così puoi avere la torta e mangiarla anche:

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

In Javascript, poiché è un linguaggio dinamico, è persino possibile aggiungere valori di enumerazione al set in un secondo momento:

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

Ricorda, i campi dell'enum (valore, nome e codice in questo esempio) non sono necessari per il controllo dell'identità e sono lì solo per comodità. Inoltre, il nome della proprietà size non deve essere necessariamente codificato, ma può anche essere impostato dinamicamente. Quindi, supponendo che tu conosca solo il nome per il tuo nuovo valore enum, puoi comunque aggiungerlo senza problemi:

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

Ovviamente ciò significa che alcune ipotesi non possono più essere fatte (quel valore rappresenta l'ordine corretto per la dimensione, ad esempio).

Ricorda che in Javascript un oggetto è come una mappa o una tabella hash. Un insieme di coppie nome-valore. Puoi passarci sopra o manipolarli altrimenti senza sapere molto su di loro in anticipo.

PER ESEMPIO:

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

E a proposito, se sei interessato ai namespace, potresti voler dare un'occhiata alla mia soluzione per uno spazio dei nomi semplice ma potente e la gestione delle dipendenze per javascript: Pacchetti JS


477
2018-03-04 22:31



Bottom line: non è possibile.

Puoi fingere, ma non otterrai la sicurezza del tipo. Generalmente questo viene fatto creando un semplice dizionario di valori stringa mappati a valori interi. Per esempio:

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

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

Il problema con questo approccio? È possibile ridefinire accidentalmente il proprio enumerante o avere per errore valori di enumerazione duplicati. Per esempio:

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

modificare 

Che mi dici di Object.freeze di Artur Czajka? Non funzionerebbe per impedirti di impostare il lunedì a giovedì? - Fry Quad

Assolutamente, Object.freeze risolverebbe completamente il problema mi sono lamentato. Vorrei ricordare a tutti che quando ho scritto quanto sopra, Object.freeze non esisteva davvero.

Ora .... ora ne apre un po ' molto possibilità interessanti.

Modifica 2
Ecco una buona libreria per creare enumerazioni.

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

Anche se probabilmente non si adatta a tutti gli usi validi dell'enumerazione, è molto lungo.


79
2017-08-21 20:56



Ecco cosa vogliamo tutti:

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

Ora puoi creare le tue enumerazioni:

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

In questo modo, le costanti possono essere acese nel solito modo (YesNo.YES, Color.GREEN) e ottengono un valore int in sequenza (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

È inoltre possibile aggiungere metodi, utilizzando Enum.prototype:

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


Modifica - piccolo miglioramento - ora con varargs: (purtroppo non funziona correttamente su IE: S ... dovrebbe restare con la versione precedente quindi)

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



Nella maggior parte dei browser moderni, c'è un simbolo tipo di dati primitivi che può essere utilizzato per creare un'enumerazione. Garantirà la sicurezza del tipo dell'enum in quanto ogni valore simbolico è garantito da JavaScript per essere unico, vale a dire. Symbol() != Symbol(). Per esempio:

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

Per semplificare il debug, è possibile aggiungere una descrizione ai valori enum:

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

Demo Plunker

Sopra GitHub puoi trovare un wrapper che semplifica il codice necessario per inizializzare l'enumerazione:

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



Ho giocato con questo, come amo le mie enumerazioni. =)

utilizzando Object.defineProperty Penso di aver trovato una soluzione alquanto valida.

Ecco un jsfiddle: http://jsfiddle.net/ZV4A6/

Usando questo metodo, dovresti (in teoria) essere in grado di chiamare e definire valori enum per qualsiasi oggetto, senza influenzare altri attributi di quell'oggetto.

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

Causa dell'attributo writable:false Questo dovrebbero rendilo sicuro.

Quindi dovresti essere in grado di creare un oggetto personalizzato, quindi chiamare Enum() su di essa. I valori assegnati iniziano da 0 e incrementano per articolo.

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



Questo è vecchio, lo so, ma il modo in cui è stato implementato tramite l'interfaccia TypeScript è:

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

Questo ti permette di guardare su entrambi MyEnum.Bar che restituisce 1, e MyEnum[1] che restituisce "Bar" indipendentemente dall'ordine di dichiarazione.


17
2018-06-24 16:11