Je reconstruis un ancien projet Java en Javascript et me suis rendu compte qu'il n'y avait pas de bonne façon de faire des énumérations dans JS.
Le mieux que je puisse trouver est:
const Colors = {
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
};
Object.freeze(Colors);
La const
empêche la réattribution de Colors
et le gel empêche la mutation des clés et des valeurs. J'utilise des symboles pour que Colors.RED
ne soit pas égal à 0
ou à quoi que ce soit d'autre que lui-même.
Y at-il un problème avec cette formulation? Y a-t-il un meilleur moyen?
(Je sais que cette question est un peu répétitive, mais tous les Q/As précédents sont assez anciens et ES6 nous offre de nouvelles fonctionnalités.)
EDIT:
Une autre solution, qui traite le problème de la sérialisation, mais je pense qu’il reste des problèmes de domaine:
const enumValue = (name) => Object.freeze({toString: () => name});
const Colors = Object.freeze({
RED: enumValue("Colors.RED"),
BLUE: enumValue("Colors.BLUE"),
GREEN: enumValue("Colors.GREEN")
});
En utilisant les références d'objet comme valeurs, vous obtenez le même évitement de collision que les symboles.
Y a-t-il un problème avec cette formulation?
Je n'en vois pas.
Y a-t-il un meilleur moyen?
Je réduirais les deux déclarations en une seule:
const Colors = Object.freeze({
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
});
Si vous n'aimez pas le passe-partout, comme les appels répétés Symbol
, vous pouvez bien sûr aussi écrire une fonction d'assistance makeEnum
qui crée la même chose à partir d'une liste de noms.
Bien que vous utilisiez Symbol
comme valeur d'enum pour les cas d'utilisation simples, il peut s'avérer utile de donner des propriétés aux énumérations. Cela peut être fait en utilisant un Object
en tant que valeur enum contenant les propriétés.
Par exemple, nous pouvons donner à chacune des Colors
un nom et une valeur hexadécimale:
/**
* Enum for common colors.
* @readonly
* @enum {{name: string, hex: string}}
*/
const Colors = Object.freeze({
RED: { name: "red", hex: "#f00" },
BLUE: { name: "blue", hex: "#00f" },
GREEN: { name: "green", hex: "#0f0" }
});
L'inclusion de propriétés dans l'énumération évite d'avoir à écrire des instructions switch
(et éventuellement d'oublier de nouveaux cas dans les instructions switch lorsqu'une énumération est étendue). L'exemple montre également les propriétés et types d'énumération documentés avec l'annotation annotation d'énumération JSDoc .
L'égalité fonctionne comme prévu avec Colors.RED === Colors.RED
étant true
et Colors.RED === Colors.BLUE
étant false
.
Comme mentionné ci-dessus, vous pouvez également écrire une fonction d'assistance makeEnum()
:
function makeEnum(arr){
let obj = {};
for (let val of arr){
obj[val] = Symbol(val);
}
return Object.freeze(obj);
}
Utilisez-le comme ceci:
const Colors = makeEnum(["red","green","blue"]);
let startColor = Colors.red;
console.log(startColor); // Symbol(red)
if(startColor == Colors.red){
console.log("Do red things");
}else{
console.log("Do non-red things");
}
Vérifiez comment TypeScript le fait-il . Fondamentalement, ils font ce qui suit:
const MAP = {};
MAP[MAP[1] = 'A'] = 1;
MAP[MAP[2] = 'B'] = 2;
MAP['A'] // 1
MAP[1] // A
Utilisez des symboles, geler un objet, tout ce que vous voulez.
Ceci est mon approche personnelle.
class ColorType {
static get RED () {
return "red";
}
static get GREEN () {
return "green";
}
static get BLUE () {
return "blue";
}
}
// Use case.
const color = Color.create(ColorType.RED);
Vous pouvez vérifier Enumify , une très bonne bibliothèque pour les énumérations ES6.
Si vous n'avez pas besoin de pure ES6 et que vous pouvez utiliser TypeScript, il possède un Nice enum
:
Peut-être que cette solution? :)
function createEnum (array) {
return Object.freeze(array
.reduce((obj, item) => {
if (typeof item === 'string') {
obj[item] = Symbol(item)
}
return obj
}, {}))
}