2316 votes

Comment puis-je garantir que la définition de mes enums ne change pas en JavaScript ?

Est-ce que les objets suivants rempliraient toutes les caractéristiques que les enums ont en JavaScript ? Quelque chose comme :

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

// later on

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

Ou y a-t-il un autre moyen de le faire ?

174 votes

N'utilisez pas 0 comme un numéro d'énumération. Sauf s'il est utilisé pour quelque chose qui n'a pas été défini. JS traite false || undefined || null || 0 || "" || '' || NaN tous de la même valeur lorsqu'on les compare en utilisant == .

209 votes

@matsko n'est-ce pas simplement un argument contre l'utilisation de == ?

8 votes

0 == null renvoie à faux

1153voto

Artur Czajka Points 3327

Depuis la version 1.8.5, il est possible de sceller et congeler l'objet donc définissez ce qui précède comme :

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

ou

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

et voilà ! Les enums JS.

Cependant, cela ne vous empêche pas d'attribuer une valeur non désirée à une variable, ce qui est souvent le principal objectif des enums :

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

Une façon de garantir un degré plus élevé de sécurité des types (avec des enums ou autres) est d'utiliser un outil tel que TypeScript ou Débit .

Les citations ne sont pas nécessaires mais je les ai gardées par souci de cohérence.

6 votes

Selon Wikipédia ( fr.wikipedia.org/wiki/JavaScript#Versions ) il est applicable à Firefox 4, IE 9, Opera 11.60 et je sais qu'il fonctionne dans Chrome.

85 votes

C'est la bonne réponse en 2012. Plus simple : var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... }); . Vous n'avez pas besoin de spécifier un id, vous pouvez simplement utiliser un objet vide pour comparer les enums. if (incommingEnum === DaysEnum.monday) //incommingEnum is monday

38 votes

Pour une compatibilité descendante, if (Object.freeze) { Object.freeze(DaysEnum); }

625voto

Gareth Points 42402

Ce n'est pas vraiment une réponse, mais je dirais que ça marche très bien, personnellement.

Cela dit, puisque les valeurs n'ont pas d'importance (vous avez utilisé 0, 1, 2), j'utiliserais une chaîne de caractères significative au cas où vous voudriez afficher la valeur actuelle.

389 votes

Cela a été dit dans une autre réponse, mais puisque cette réponse est la réponse acceptée, je vais la poster ici. La solution de l'OP est correcte. Elle sera encore meilleure, cependant, si elle est utilisée avec Object.freeze() . Cela empêchera un autre code de modifier les valeurs de l'enum. Exemple : var ColorEnum = Object.freeze({RED: 0, GREEN: 1, BLUE: 2});

5 votes

@TolgaE merci pour cette bibliothèque ! Elle m'a inspiré non seulement pour la réduire au strict minimum, mais aussi pour ajouter quelques fonctionnalités ! J'ai bifurqué sur la vôtre et j'ai tout mis ici : github.com/BlueHuskyStudios/Micro-JS-Enum

3 votes

@Supuhstar C'est génial ! Je suis heureux que vous ayez pu l'utiliser N'hésitez pas à faire une demande de pull si vous voulez qu'il soit fusionné dans cette bibliothèque, puis je peux mettre à jour la bibliothèque npm.

519voto

Stijn de Witt Points 3515

UPDATE

Merci pour tous les votes positifs, mais je ne pense pas que ma réponse ci-dessous soit la meilleure façon d'écrire des enums en JavaScript. Voir mon article de blog pour plus de détails : Enums en JavaScript .


L'alerte du nom est déjà possible :

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

Vous pouvez également faire des valeurs des objets, afin d'avoir le beurre et l'argent du beurre :

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

En JavaScript, comme il s'agit d'un langage dynamique, il est même possible d'ajouter ultérieurement des valeurs d'énumération à l'ensemble :

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

N'oubliez pas que les champs de l'enum (valeur, nom et code dans cet exemple) ne sont pas nécessaires au contrôle d'identité et ne sont là que par commodité. De même, le nom de la propriété size n'a pas besoin d'être codé en dur, mais peut être défini dynamiquement. Ainsi, si vous ne connaissez que le nom de la nouvelle valeur de votre enum, vous pouvez l'ajouter sans problème :

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

Bien sûr, cela signifie que certaines hypothèses ne peuvent plus être faites (que la valeur représente l'ordre correct pour la taille par exemple).

Rappelez-vous, en JavaScript, un objet est comme un carte ou table de hachage . Un ensemble de paires nom-valeur. Vous pouvez les parcourir en boucle ou les manipuler d'une autre manière sans en savoir beaucoup à l'avance.

Exemple

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

À propos, si les espaces de noms vous intéressent, vous pouvez jeter un coup d'œil à ma solution pour une gestion simple mais puissante des espaces de noms et des dépendances pour JavaScript : Packages JS

0 votes

Alors comment faire pour créer simplement une TAILLE si vous n'avez que son nom ?

2 votes

@Johanisma : Ce cas d'utilisation n'a pas vraiment de sens pour les enums car leur principe est de connaître toutes les valeurs à l'avance. Cependant, rien ne vous empêche d'ajouter des valeurs supplémentaires plus tard en Javascript. Je vais ajouter un exemple à ma réponse.

2 votes

+1 pour le lien vers votre post avec l'approche des propriétés. Élégante dans la mesure où les déclarations de base sont simples, comme dans l'OP, avec une fonctionnalité de propriétés ajoutée si nécessaire.

90voto

Randolpho Points 36512

En résumé : Vous ne pouvez pas.

Vous pouvez faire semblant, mais vous n'aurez pas la sécurité du type. En général, cela se fait en créant un simple dictionnaire de valeurs de chaînes de caractères associées à des valeurs entières. Par exemple :

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

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

Le problème de cette approche ? Vous pouvez accidentellement redéfinir votre énumérateur, ou accidentellement avoir des valeurs d'énumérateur en double. Par exemple :

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

Modifier

Qu'en est-il de Object.freeze d'Artur Czajka ? Cela ne fonctionnerait-il pas pour vous empêcher de mettre le lundi au jeudi ? - Fry Quad

Absolument, Object.freeze réglerait totalement le problème dont je me suis plaint. Je voudrais rappeler à tout le monde que lorsque j'ai écrit ce qui précède, Object.freeze n'a pas vraiment existé.

Maintenant.... maintenant ça ouvre quelques très des possibilités intéressantes.

Edit 2
Voici une très bonne bibliothèque pour créer des enums.

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

Bien que cela ne corresponde probablement pas à toutes les utilisations valables des enums, cela va très loin.

107 votes

Il y a une sécurité de type en javascript ?

3 votes

Il ne faut donc pas faire correspondre les valeurs aux propriétés des objets. Utilisez un getter pour accéder à l'énumération (stockée comme une propriété de, disons, un objet "privé"). Une implémentation naïve ressemblerait à - var daysEnum = (function(){ var daysEnum = { monday: 1, tuesday: 2 }; return { get: function(value){ return daysEnum[value]; } } })(); daysEnum.get('monday'); // 1

3 votes

@Scott Evernden : bien vu. @kangax : le point est que c'est toujours un hack. Les Enums n'existent tout simplement pas en Javascript, point barre, fin de l'histoire. Même le modèle suggéré par Tim Sylvester est toujours un hack moins qu'idéal.

61voto

Andre 'Fi' Points 211

Voici ce que nous voulons tous :

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

Maintenant vous pouvez créer vos enums :

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

En faisant cela, les constantes peuvent être accédées de la manière habituelle (OuiNon.OUI, Couleur.VERT) et elles obtiennent une valeur int séquentielle (NON = 0, OUI = 1 ; ROUGE = 0, VERT = 1, BLEU = 2).

Vous pouvez également ajouter des méthodes, en utilisant 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 */
};

Edit - petite amélioration - maintenant avec varargs : (malheureusement cela ne fonctionne pas correctement sur IE :S... je devrais m'en tenir à la version précédente alors)

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

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

0 votes

J'aime la simplicité de cette réponse !

0 votes

@Marquizzo (et OP) J'ai créé une version améliorée basée sur cette réponse : stackoverflow.com/a/60309416/1599699

0 votes

@Andrew J'ai créé une réponse distincte et beaucoup plus réfléchie, soigneusement étudiée et soigneusement contrôlée que j'ai utilisée en production à de nombreuses reprises : stackoverflow.com/a/50355530/5601591

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X