Enum type pour javascript

Contenu du snippet

Pour ceux qui ont touché à Java, il est frustrant de ne pas pouvoir trouver un équivalent du type énuméré (Enum) en javascript. Cette implémentation se base sur le respect de certaines règles qu'un Enum doit prendre en compte:
- Initialisation (simple): Type = new Enum('type1', 'type2', 'type3');
- Chaînage: un Enum est de type 'Enum' et ses éléments sont de type 'EnumItem'
- Constance: interdire la modification de l'Enum une fois instancié
- Les éléments doivent être lisible (toString) et comparable (compareTo) (pour ceux qui aiment Java).

En réalité, c'est la conjonction des règles 2 et 3 qui est le plus compliqué à mettre en oeuvre. En d'autres termes, le problème revient à ajouter un accesseur dynamiquement. Depuis JavaScript 1.8.5, il est possible d'ajouter des propriétés dynamiquement en utilisant la méthode statique 'defineProperty' de la classe 'Object'. De ce fait, contrairement à d'anciennes versions, il n'est plus utile d'évaluer le code pour définir les propriétés à la volée. La seule solution implémentée ici crée, pour chaque élément, une propriété en lecture seule dont la valeur est une instance de la classe 'EnumItem'; ce qui respecte bien les règles 2 et 3.

Cette solution s'approche un peu plus du type énuméré que l'on peut rencontrer en Java, même s'il est vrai que c'est surtout l'exécution qui y ressemble non la mécanique en tant que telle.

Source / Exemple :

/*******************************************************************************


* Title: Enum.js

* Description:_

*  Enum for JS. 
 *


* This class implements the Enum type as an Object's concrete type.

* In fact, it is more a bypass to simulate the Enum paradigm than a real

* implementation.
 *


* By creating a new Enum object, each element of the enumeration is seen as

* as an object (of type EnumItem) and not as a String or a number (like some

* simple implementation). The static function 'compare' (a masquerade for to

* ease the use of 'comparTo') act as a deep equality (identity).
 *


* Example:_

* Type = new Enum('type1', 'type2', 'type3'); // init

* Enum.compare(Type.type1, Type.type2); // return false

* Type.type1 = ... // has no effect

* Type.type1 // return an object of type 'EnumItem'
 *


* Author: Thierry SORG a.k.a TriumpHS

* E-mail: triumphs @ devmen.net

* Date: 03.02.12 (EU date format)
 *


* Revision date: 30.08.2012 (EU date format)



function Enum(){
 // Class of each item (useful for the identity operation of 'compareTo')
 EnumItem = function(label){
  var label = label;
  // this.compareTo = function(t){ return this === t; };
  // this.toString = function(){ return label };
  Object.defineProperty(this, 'compareTo',{
   value : function(t){ return this === t; } });
  Object.defineProperty(this, 'toString',{
   value : function(){ return label; } });
 }; // PRIVATE CLASS: EnumElmt
 
 //if(arguments.length == 0) throw new Error('Empty enumeration.');
 
 var labels = new Array(); // for optional method toArray
 var items = {};
 var addItem = function(label){
  items[label] = new EnumItem(label);
 }
 var getInstance = function(label){ return items[label]; }
  
 if(arguments.length == 1) labels = Array.prototype.slice.call(arguments[0]);
 else labels = Array.prototype.slice.call(arguments);

 labels.forEach(function(e, i, l){
  addItem(e);
  Object.defineProperty(this,e,{value : getInstance(e) });
 }, this);
 
 Object.defineProperties(this, {
  'valueOf':{value : function(label){ return items[label]; } },
  'toArray': // Optional methods 
   {value : function(){ return Array.prototype.slice.call(labels); } },
  'hasItem': // Optional methods 
   {value : function(e){ return getInstance(e.toString())!= undefined; } }
 }); 
};// CLASS: Enum

Enum.compare = function(t1, t2){
 try{ return t1.compareTo(t2); }
 catch(ignored){ return false;}
}; // STATIC FUNCTION: Enum.compare

Conclusion :

Au final ce script permet d'instancier un objet comme un type énuméré ayant des éléments qui sont des objets dont le type est issu du type énuméré.

Exemple:
EventType = new Enum('click', 'mouseover', 'blur', 'submit');

Où l'objet 'EventType' est un Enum et chacun de ses éléments, tel que 'EventType.click', est un EnumItem.
C'est donc une implémentation simple du paradigme. Elle a aussi comme effet de bord d'être soumise à l'héritage:

EventTypeEnum = function(){}
EventTypeEnum.prototype = new Enum('click', 'mouseover', 'blur', 'submit');
EventTypeEnum.prototype.constructor = EventTypeEnum;
EventType = new EventTypeEnum();

Contrairement au cas standard, cet exemple montre qu'il est possible de créer un type Enum spécifique (ici lié aux évènements - Event). Cette forme est tout aussi fonctionnelle que la précédente, mais à l'avantage d'être plus lisible.

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.