Quelle est la syntaxe préférée pour définir enums dans JavaScript?

Quelle est la syntaxe préférée pour définir enums 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 idiome plus préférable?

1721
demandé sur Flip 2008-11-13 22:09:06

30 réponses

depuis 1.8.5 il est possible de sceller et congeler l'objet, donc définir ce qui précède comme:

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

ou

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

et voilà! Js enums.

cependant, cela ne vous empêche pas d'attribuer une valeur indésirable à une variable, ce qui est souvent le but principal d'enums:

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

une façon d'assurer un degré plus élevé de sécurité de type (avec ou sans enum) est d'utiliser un outil comme Tapuscrit ou Flux .

Source

les citations ne sont pas nécessaires mais je les ai gardées pour plus de cohérence.

583
répondu Artur Czajka 2018-07-25 00:04:55

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

ayant dit cela, puisqu'il n'importe pas ce que les valeurs sont (vous avez utilisé 0, 1, 2), j'utiliserais une chaîne significative dans le cas où vous jamais voulu produire la valeur courante.

585
répondu Gareth 2008-11-13 19:22:44

mise à JOUR : Merci à tous pour les upvotes tout le monde, mais je ne pense pas que ma réponse ci-dessous est la meilleure façon de rédiger les enums en Javascript plus. Voir mon billet de blog pour plus de détails: Enums en Javascript .


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

alternativement, vous pouvez faire les objets de valeurs, de sorte que vous pouvez avoir le gâteau et le manger aussi:

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 c'est un langage dynamique, il est même possible d'ajouter des valeurs enum plus tard:

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

rappelez-vous, les champs de l'enum (valeur, nom et code dans cet exemple) ne sont pas nécessaires pour le contrôle d'identité et sont seulement là pour la commodité. En outre, le nom de la propriété size elle-même n'a pas besoin d'être codé en dur, mais peut également être défini dynamiquement. Donc supposons que vous ne connaissez que le nom de votre nouvelle valeur enum, vous pouvez encore ajouter sans problèmes:

// 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 (cette valeur représente l'ordre correct pour la taille par exemple).

rappelez-vous, en Javascript un objet est comme une carte ou un hashtable. Un ensemble de paires nom-valeur. Vous pouvez les passer en boucle ou les manipuler sans en savoir plus à l'avance.

E. G:

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

et btw, si vous êtes intéressé par les namespaces, vous pouvez jeter un oeil à ma solution pour la gestion simple mais puissante des namespace et des dépendances pour javascript: paquets js

480
répondu Stijn de Witt 2017-09-09 18:41:26

conclusion: vous ne pouvez pas.

vous pouvez faire semblant, mais vous n'obtiendrez pas la sécurité de type. Typiquement ceci est fait en créant un dictionnaire simple des valeurs de chaîne de caractères mappées à des valeurs entières. Par exemple:

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

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

Le problème avec cette approche? Vous pouvez accidentellement redéfinir votre énumérant, ou accidentellement avoir des valeurs de énumérant dupliquées. Par exemple:

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

Modifier

Qu'en est-il de L'objet D'Artur Czajka.congeler? Cela ne vous empêcherait-il pas de fixer du lundi au jeudi? - Fry Quad

absolument, Object.freeze ça réglerait le problème dont je me plaignais. Je voudrais rappeler à tout le monde que lorsque j'ai écrit ce qui précède, Object.freeze n'existait pas vraiment.

maintenant.... maintenant, il ouvre quelques très intéressant possibilité.

Edit 2

Voici une très bonne librairie pour créer des énumérations.

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

bien qu'il ne corresponde probablement pas à toutes les utilisations valides d'enums, il va très loin.

80
répondu Randolpho 2012-06-06 16:09:02

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 évaluées de la manière habituelle (YesNo.Oui, La couleur.Vert) et ils 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 */
};



Modifier-petite amélioration - maintenant, avec varargs: (malheureusement, cela ne fonctionne pas correctement sur IE: S... devrait s'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');
46
répondu Andre 'Fi' 2011-07-19 01:21:59

dans la plupart des navigateurs modernes, il ya un symbole type de données primitives qui peuvent être utilisés pour créer un dénombrement. Il assurera la sécurité de type de l'enum puisque chaque valeur de symbole est garantie par JavaScript pour être unique, i.e. Symbol() != Symbol() . Par exemple:

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

pour simplifier le débogage, vous pouvez ajouter une description aux valeurs enum:

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

Plunker démo

Sur GitHub vous pouvez trouver un wrapper qui simplifie le code requis pour initialiser l'enum:

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
44
répondu Vitalii Fedorenko 2017-12-31 23:33:29

j'ai joué avec ça, comme j'aime mes énums. = )

en utilisant Object.defineProperty je pense que j'ai trouvé une solution quelque peu viable.

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

utilisant cette méthode.. vous devriez (en théorie) être capable d'appeler et de définir des valeurs enum pour n'importe quel objet, sans affecter les autres attributs de cet objet.

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

parce que de l'attribut writable:false , ce devrait être .

donc vous devriez pouvoir créer un objet personnalisé, puis appeler Enum() dessus. Les valeurs attribuées commencent à 0 et augmentent par item.

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3
23
répondu Duncan 2013-08-21 17:20:55

c'est un vieux que je connais, mais la façon dont il a été mis en œuvre depuis via L'interface TypeScript est:

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

cela vous permet de consulter à la fois MyEnum.Bar qui renvoie 1, et MyEnum[1] qui renvoie" Bar " quel que soit l'ordre de la déclaration.

18
répondu Rob Hardy 2013-06-24 16:11:14

C'est la solution que j'utilise.

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

et vous définissez vos énums comme ceci:

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

Et voici comment vous accédez à vos énums:

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

j'utilise habituellement les 2 dernières méthodes pour cartographier les énums des objets de message.

Certains avantages à cette approche:

  • facile à déclarer enums
  • facile d'accéder à votre enum
  • vos énums peuvent être des types complexes
  • la classe Enum a une sorte de cache associatif si vous utilisez getByValue beaucoup

Certains inconvénients:

  • la gestion de la mémoire est un peu désordonnée, car je garde les références aux enums
  • Toujours pas de sécurité de type
15
répondu Chris 2012-05-15 09:31:57

si vous utilisez Backbone , vous pouvez obtenir la fonctionnalité enum complète (trouver par id, nom, membres personnalisés) GRATUITEMENT en utilisant Backbone.Collection .

// enum instance members, optional
var Color = Backbone.Model.extend({
    print : function() {
        console.log("I am " + this.get("name"))
    }
});

// enum creation
var Colors = new Backbone.Collection([
    { id : 1, name : "Red", rgb : 0xFF0000},
    { id : 2, name : "Green" , rgb : 0x00FF00},
    { id : 3, name : "Blue" , rgb : 0x0000FF}
], {
    model : Color
});

// Expose members through public fields.
Colors.each(function(color) {
    Colors[color.get("name")] = color;
});

// using
Colors.Red.print()
12
répondu Yaroslav 2012-04-24 14:04:46

dans ES7 , vous pouvez faire un ENUM élégant en s'appuyant sur des attributs statiques:

class ColorEnum  {
    static RED = 0 ;
    static GREEN = 1;
    static BLUE = 2;
}

puis

if (currentColor === ColorEnum.GREEN ) {/*-- coding --*/}

l'avantage ( d'utiliser la classe au lieu de l'objet littéral) est d'avoir une classe mère Enum alors tous vos Enums étend cette classe.

 class ColorEnum  extends Enum {/*....*/}
12
répondu Abdennour TOUMI 2017-01-06 07:07:59

créer un objet littéral:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};
11
répondu hvdd 2017-06-01 17:03:41

la "syntaxe perforée" par la plupart des gens a déjà été énumérée ci-dessus. Toutefois, il y a un problème primordial: la performance. Pas une seule des réponses ci-dessus est très performant dans le moindre et ils gonflent tous votre taille de code à l'extrême. Pour une performance réelle, une facilité de lecture du code, et une réduction sans précédent de la taille du code par minification, c'est la bonne façon de procéder aux énumérations.

const ENUM_COLORENUM_RED   = 0,
      ENUM_COLORENUM_GREEN = 1,
      ENUM_COLORENUM_BLUE  = 2,
      ENUMLEN_COLORENUM    = 3;

// later on

if(currentColor == ENUM_COLORENUM_RED) {
   // whatever
}

en Outre, cette syntaxe permet classe claire et concise s'étendant comme vu ci-dessous.

(Longueur: 2,450 octets)

(function(window){
    "use strict";
    var parseInt = window.parseInt

    const ENUM_PIXELCOLOR_TYPE = 0, // is a ENUM_PIXELTYPE
          ENUMLEN_PIXELCOLOR   = 1,
          ENUM_SOLIDCOLOR_R    = ENUMLEN_PIXELCOLOR+0,
          ENUM_SOLIDCOLOR_G    = ENUMLEN_PIXELCOLOR+1,
          ENUM_SOLIDCOLOR_B    = ENUMLEN_PIXELCOLOR+2,
          ENUMLEN_SOLIDCOLOR   = ENUMLEN_PIXELCOLOR+3,
          ENUM_ALPHACOLOR_R    = ENUMLEN_PIXELCOLOR+0,
          ENUM_ALPHACOLOR_G    = ENUMLEN_PIXELCOLOR+1,
          ENUM_ALPHACOLOR_B    = ENUMLEN_PIXELCOLOR+2,
          ENUM_ALPHACOLOR_A    = ENUMLEN_PIXELCOLOR+3,
          ENUMLEN_ALPHACOLOR   = ENUMLEN_PIXELCOLOR+4,
          ENUM_PIXELTYPE_SOLID = 0,
          ENUM_PIXELTYPE_ALPHA = 1,
          ENUM_PIXELTYPE_UNKNOWN = 2,
          ENUMLEN_PIXELTYPE    = 2;

    function parseHexColor(rawstr) {
        rawstr = rawstr.trim().substring(1);
        var result = [];
        if (rawstr.length === 8) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA;
            result[ENUM_ALPHACOLOR_R] = parseInt(rawstr.substring(0,2), 16);
            result[ENUM_ALPHACOLOR_G] = parseInt(rawstr.substring(2,4), 16);
            result[ENUM_ALPHACOLOR_B] = parseInt(rawstr.substring(4,6), 16);
            result[ENUM_ALPHACOLOR_A] = parseInt(rawstr.substring(4,6), 16);
        } else if (rawstr.length === 4) {
            result[ENUM_ALPHACOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
            result[ENUM_ALPHACOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
            result[ENUM_ALPHACOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
            result[ENUM_ALPHACOLOR_A] = parseInt(rawstr[3], 16) * 0x11;
        } else if (rawstr.length === 6) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
            result[ENUM_SOLIDCOLOR_R] = parseInt(rawstr.substring(0,2), 16);
            result[ENUM_SOLIDCOLOR_G] = parseInt(rawstr.substring(2,4), 16);
            result[ENUM_SOLIDCOLOR_B] = parseInt(rawstr.substring(4,6), 16);
        } else if (rawstr.length === 3) {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID;
            result[ENUM_SOLIDCOLOR_R] = parseInt(rawstr[0], 16) * 0x11;
            result[ENUM_SOLIDCOLOR_G] = parseInt(rawstr[1], 16) * 0x11;
            result[ENUM_SOLIDCOLOR_B] = parseInt(rawstr[2], 16) * 0x11;
        } else {
            result[ENUM_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_UNKNOWN;
        }
        return result;
    }

    // the red component of green
    console.log(parseHexColor("#0f0")[ENUM_SOLIDCOLOR_R]);
    // the alpha of transparent purple
    console.log(parseHexColor("#f0f7")[ENUM_ALPHACOLOR_A]); 
    // the enumerated array for turquoise
    console.log(parseHexColor("#40E0D0"));
})(self);

certains peuvent dire que c'est moins pratique que d'autres solutions: Il dispose de tonnes d'espace, il faut beaucoup de temps pour écrire, et il n'est pas enduit de syntaxe de sucre. Oui, ces gens auraient raison s'ils ne minifient pas leur code. Toutefois, aucune personne raisonnable ne laisserait de code non réduit dans le produit final. Pour cette minification, Closure Compiler est le meilleur que j'ai encore à trouver. L'accès en ligne peut être trouvé ici . Le compilateur de fermeture est capable de prendre toutes ces données d'énumération et de les mettre en ligne, faisant courir votre javascript super duper rapide et être super duper petit. Observer.

(Longueur: 605 octets)

'use strict';(function(e){function d(a){a=a.trim().substring(1);var b=[];8===a.length?(b[0]=1,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16),b[4]=c(a.substring(4,6),16)):4===a.length?(b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16),b[4]=17*c(a[3],16)):6===a.length?(b[0]=0,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16)):3===a.length?(b[0]=0,b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16)):b[0]=2;return b}var c=
e.parseInt;console.log(d("#0f0")[1]);console.log(d("#f0f7")[4]);console.log(d("#40E0D0"))})(self);

voyons maintenant la taille du fichier équivalent sans aucune de ces énumérations.

Source sans énumérations (longueur: 1,973 octets (plus court!))

Minifiés Sans Énumérations (longueur: 843 octets ( plus ))

comme nous l'avons vu, sans énumérations, le code source est plus court au prix d'un code plus grand. Je ne sais pas pour vous, je sais pour sûr que je n'aime pas intégrer le code source dans le produit final, ce qui rend cette énumération manière de loin supérieure. Ajoutez à cela que cette forme d'énumération est plus rapide. En effet, cette forme d'énumération est le chemin à parcourir.

10
répondu Jack Giffin 2018-08-30 10:30:16

vos réponses sont beaucoup trop compliquées

var buildSet = function(array) {
  var set = {};
  for (var i in array) {
    var item = array[i];
    set[item] = item;
  }
  return set;
}

var myEnum = buildSet(['RED','GREEN','BLUE']);
// myEnum.RED == 'RED' ...etc
9
répondu Xeltor 2014-05-15 04:20:02

j'ai modifié la solution D'André 'Fi':

  function Enum() {
    var that = this;
    for (var i in arguments) {
        that[arguments[i]] = i;
    }
    this.name = function(value) {
        for (var key in that) {
            if (that[key] == value) {
                return key;
            }
        }
    };
    this.exist = function(value) {
        return (typeof that.name(value) !== "undefined");
    };
    if (Object.freeze) {
        Object.freeze(that);
    }
  }

essai:

var Color = new Enum('RED', 'GREEN', 'BLUE');
undefined
Color.name(Color.REDs)
undefined
Color.name(Color.RED)
"RED"
Color.exist(Color.REDs)
false
Color.exist(Color.RED)
true
8
répondu David Miró 2013-04-12 17:04:16

Utiliser Javascript Proxies

une caractéristique très bénéfique des Enums que vous obtenez des langues traditionnelles est qu'ils explosent (jeter une erreur de compilation) si vous essayez d'accéder à un recenseur qui n'existe pas.

outre le gel de la structure moqueuse de l'enum pour éviter que des valeurs supplémentaires ne soient accidentellement/malicieusement ajoutées, aucune des autres réponses n'aborde cette caractéristique intrinsèque des Enums.

comme vous le savez probablement, l'accès à des membres non existants en JavaScript renvoie simplement undefined et ne fait pas exploser votre code. Puisque les énumérateurs sont des constantes prédéfinies (c.-à-d. les jours de la semaine), il ne devrait jamais y avoir un cas où un énumérateur devrait être non défini.

Don't get me wrong, JavaScript du comportement de retour "à la 151910920" lors de l'accès aux propriétés non définies est en fait une fonctionnalité très puissante de la langue, mais ce n'est pas une fonction que vous voulez lorsque vous essayez de vous moquer des structures traditionnelles Enum.

C'est ici que les objets Proxy brillent. Les approximations ont été normalisées dans le langage avec L'introduction de ES6 (ES2015). Voici la description de MDN:

l'objet Proxy est utilisé pour définir le comportement personnalisé pour les opérations fondamentales (par ex. recherche de propriété, assignation, énumération, fonction). invocation, etc).

similaire à un web proxy serveur, les proxies JavaScript sont capables d'intercepter des opérations sur des objets (avec l'utilisation de "pièges", appelez-les crochets si vous le souhaitez) et vous permettent d'effectuer divers contrôles, actions et/ou manipulations avant qu'ils ne soient terminés (ou dans certains cas d'arrêter les opérations tout à fait ce qui est exactement ce que nous voulons faire si et quand nous essayons de faire référence à un énumérateur qui n'existe pas).

voici un exemple artificiel qui utilise L'objet Proxy pour imiter des Enums. Les recenseurs dans cet exemple est une méthode HTTP standard (par exemple" GET"," POST", etc.):

// Generic Factory Function for creating enums (10 lines)
// Feel free to add this to your utility library in 
// your codebase and profit! Note: As Proxies are an ES6 
// feature, some browsers/clients may not support it and 
// you may need to transpile using a service like babel

function createEnum(enumObj) {

  // Instantiating a `Proxy` object requires two parameters, 
  // a `target` object and a `handler`. We first define the handler,
  // then use the handler to instantiate a Proxy.

  // a proxy handler is simply an object whose properties
  // are functions which define the behavior of the proxy 
  // when an operation is performed on it. For enums, we 
  // need to define behavior that lets us check what enumerator
  // is being accessed. This can be done by defining the "get" trap
  
  const enumHandler = {
    get: function(target, name) {
      if (target[name]) {
        return target[name]
      }
      throw new Error(`No such enumerator: ${name}`)
    }
  }
  
  
  // Freeze the target object to prevent modifications
  return new Proxy(Object.freeze(enumObj), enumHandler)
}


// Now that we have a generic way of creating Enums, lets create our first Enum!
const httpMethods = createEnum({
  DELETE: "DELETE",
  GET: "GET",
  OPTIONS: "OPTIONS",
  PATCH: "PATCH",
  POST: "POST",
  PUT: "PUT"
})

// Sanity checks
console.log(httpMethods.DELETE) 
// logs "DELETE"

httpMethods.delete = "delete" 
// no effect due to Object.freeze, fails silently (no error thrown)

try {
  console.log(httpMethods.delete) 
} catch (e) {
  console.log("Error: ", e.message)
}
// throws an error "Uncaught Error: No such enumerator: delete"

mis à part: qu'est-ce qu'un mandataire?

je me souviens quand j'ai commencé à voir le mot proxy partout, ça n'avait aucun sens pour moi depuis longtemps. Si c'est vous en ce moment, je pense qu'un moyen facile de généraliser les mandataires est de les considérer comme des logiciels, des institutions, ou même personnes qui agissent comme intermédiaires ou intermédiaires entre deux serveurs, entreprises ou personnes.

7
répondu Govind Rai 2018-05-18 03:11:13

IE8 ne supporte pas la méthode freeze ().

Source: http://kangax.github.io/compat-table/es5 / , cliquez sur " Afficher les navigateurs obsolètes?"sur le dessus, et de vérifier IE8 & gel ligne col intersection.

dans mon projet de jeu actuel, j'ai utilisé ci-dessous, car peu de clients utilisent encore IE8:

var CONST_WILD_TYPES = {
    REGULAR: 'REGULAR',
    EXPANDING: 'EXPANDING',
    STICKY: 'STICKY',
    SHIFTING: 'SHIFTING'
};

Nous pourrions aussi le faire:

var CONST_WILD_TYPES = {
    REGULAR: 'RE',
    EXPANDING: 'EX',
    STICKY: 'ST',
    SHIFTING: 'SH'
};

ou même ceci:

var CONST_WILD_TYPES = {
    REGULAR: '1',
    EXPANDING: '2',
    STICKY: '3',
    SHIFTING: '4'
};

le dernier, semble le plus efficace pour la chaîne, il réduit votre bande passante totale si vous avez le serveur et le client échangeant ces données.

Bien sûr, maintenant il est de votre devoir de vous assurer qu'il n'y a pas de conflits dans les données (RE, EX, etc. doit être unique, aussi 1, 2, etc. devrait être unique). Notez que vous avez besoin de les maintenir à tout jamais pour une rétrocompatibilité.

affectation:

var wildType = CONST_WILD_TYPES.REGULAR;

comparaison:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}
5
répondu Manohar Reddy Poreddy 2016-08-02 04:50:50

j'ai fait une classe Enum qui peut aller chercher des valeurs et des noms à O(1). Il peut aussi générer un tableau D'objets contenant tous les noms et toutes les valeurs.

function Enum(obj) {
    // Names must be unique, Values do not.
    // Putting same values for different Names is risky for this implementation

    this._reserved = {
        _namesObj: {},
        _objArr: [],
        _namesArr: [],
        _valuesArr: [],
        _selectOptionsHTML: ""
    };

    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            this[k] = obj[k];
            this._reserved._namesObj[obj[k]] = k;
        }
    }
}
(function () {
    this.GetName = function (val) {
        if (typeof this._reserved._namesObj[val] === "undefined")
            return null;
        return this._reserved._namesObj[val];
    };

    this.GetValue = function (name) {
        if (typeof this[name] === "undefined")
            return null;
        return this[name];
    };

    this.GetObjArr = function () {
        if (this._reserved._objArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push({
                            Name: k,
                            Value: this[k]
                        });
            }
            this._reserved._objArr = arr;
        }
        return this._reserved._objArr;
    };

    this.GetNamesArr = function () {
        if (this._reserved._namesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(k);
            }
            this._reserved._namesArr = arr;
        }
        return this._reserved._namesArr;
    };

    this.GetValuesArr = function () {
        if (this._reserved._valuesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(this[k]);
            }
            this._reserved._valuesArr = arr;
        }
        return this._reserved._valuesArr;
    };

    this.GetSelectOptionsHTML = function () {
        if (this._reserved._selectOptionsHTML.length == 0) {
            var html = "";
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        html += "<option value='" + this[k] + "'>" + k + "</option>";
            }
            this._reserved._selectOptionsHTML = html;
        }
        return this._reserved._selectOptionsHTML;
    };
}).call(Enum.prototype);

vous pouvez écrire comme ceci:

var enum1 = new Enum({
    item1: 0,
    item2: 1,
    item3: 2
});

pour obtenir une valeur (comme Enums en C#):

var val2 = enum1.item2;

pour obtenir un nom pour une valeur (peut être ambigu en mettant la même valeur pour des noms différents):

var name1 = enum1.GetName(0);  // "item1"

Pour obtenir un tableau avec chaque nom et valeur dans un objet:

var arr = enum1.GetObjArr();

générera:

[{ Name: "item1", Value: 0}, { ... }, ... ]

vous pouvez aussi obtenir les options html select facilement:

var html = enum1.GetSelectOptionsHTML();

Qui tient:

"<option value='0'>item1</option>..."
5
répondu Oooogi 2016-12-08 18:22:27

une façon rapide et simple serait:

var Colors = function(){
return {
    'WHITE':0,
    'BLACK':1,
    'RED':2,
    'GREEN':3
    }
}();

console.log(Colors.WHITE)  //this prints out "0"
4
répondu user2254487 2013-10-06 22:07:47

voici quelques façons différentes d'implémenter enums dactylographiés .

la façon la plus simple est de simplement itérer un objet, en ajoutant des paires de valeurs clés inversées à l'objet. Le seul inconvénient est que vous devez définir manuellement la valeur de chacun des membres.

function _enum(list) {       
  for (var key in list) {
    list[list[key] = list[key]] = key;
  }
  return Object.freeze(list);
}

var Color = _enum({
  Red: 0,
  Green: 5,
  Blue: 2
});

// Color → {0: "Red", 2: "Blue", 5: "Green", "Red": 0, "Green": 5, "Blue": 2}
// Color.Red → 0
// Color.Green → 5
// Color.Blue → 2
// Color[5] → Green
// Color.Blue > Color.Green → false



Et voici un lodash mixin pour créer un enum en utilisant une chaîne. Alors que cette version est un peu plus en cause, il ne la numérotation automatiquement pour vous. Toutes les méthodes lodash utilisées dans cet exemple ont un équivalent JavaScript régulier, vous pouvez donc facilement les désactiver si vous le souhaitez.

function enum() {
    var key, val = -1, list = {};
    _.reduce(_.toArray(arguments), function(result, kvp) {    
        kvp = kvp.split("=");
        key = _.trim(kvp[0]);
        val = _.parseInt(kvp[1]) || ++val;            
        result[result[val] = key] = val;
        return result;
    }, list);
    return Object.freeze(list);
}    

// Add enum to lodash 
_.mixin({ "enum": enum });

var Color = _.enum(
    "Red",
    "Green",
    "Blue = 5",
    "Yellow",
    "Purple = 20",
    "Gray"
);

// Color.Red → 0
// Color.Green → 1
// Color.Blue → 5
// Color.Yellow → 6
// Color.Purple → 20
// Color.Gray → 21
// Color[5] → Blue
4
répondu Blake Bowen 2015-03-17 21:24:32

je viens de publier un paquet NPM gen_enum vous permet de créer rapidement une structure de données Enum en Javascript:

var genEnum = require('gen_enum');

var AppMode = genEnum('SIGN_UP, LOG_IN, FORGOT_PASSWORD');
var curMode = AppMode.LOG_IN;
console.log(curMode.isLogIn()); // output true 
console.log(curMode.isSignUp()); // output false 
console.log(curMode.isForgotPassword()); // output false 

une chose agréable au sujet de cet petit outil est dans l'environnement moderne (y compris nodejs et IE 9+ navigateurs) l'objet enum retourné est immuable.

pour plus d'information s'il vous plaît consulter https://github.com/greenlaw110/enumjs

Mises à jour

j'obsolète "151930920 de package et de fusion de la fonction dans constjs , qui offre plus de fonctionnalités, y compris des objets immuables, chaîne JSON de la désérialisation, les constantes de chaîne et bitmap génération, etc Caisse https://www.npmjs.com/package/constjs pour plus d'information

pour passer de gen_enum à constjs il suffit de changer l'énoncé

var genEnum = require('gen_enum');

à

var genEnum = require('constjs').enum;
4
répondu Gelin Luo 2015-05-01 23:44:40

j'ai trouvé cette approche qui est modelé sur enums en Java. Ceux-ci sont de type-sûr, et donc vous pouvez effectuer des vérifications instanceof ainsi.

vous pouvez définir des énums comme ceci:

var Days = Enum.define("Days", ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]);

Days fait maintenant référence à Days enum:

Days.Monday instanceof Days; // true

Days.Friday.name(); // "Friday"
Days.Friday.ordinal(); // 4

Days.Sunday === Days.Sunday; // true
Days.Sunday === Days.Friday; // false

Days.Sunday.toString(); // "Sunday"

Days.toString() // "Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } "

Days.values().map(function(e) { return e.name(); }); //["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
Days.values()[4].name(); //"Friday"

Days.fromName("Thursday") === Days.Thursday // true
Days.fromName("Wednesday").name() // "Wednesday"
Days.Friday.fromName("Saturday").name() // "Saturday"

La mise en œuvre:

var Enum = (function () {
    /**
     * Function to define an enum
     * @param typeName - The name of the enum.
     * @param constants - The constants on the enum. Can be an array of strings, or an object where each key is an enum
     * constant, and the values are objects that describe attributes that can be attached to the associated constant.
     */
    function define(typeName, constants) {

        /** Check Arguments **/
        if (typeof typeName === "undefined") {
            throw new TypeError("A name is required.");
        }

        if (!(constants instanceof Array) && (Object.getPrototypeOf(constants) !== Object.prototype)) {

            throw new TypeError("The constants parameter must either be an array or an object.");

        } else if ((constants instanceof Array) && constants.length === 0) {

            throw new TypeError("Need to provide at least one constant.");

        } else if ((constants instanceof Array) && !constants.reduce(function (isString, element) {
                return isString && (typeof element === "string");
            }, true)) {

            throw new TypeError("One or more elements in the constant array is not a string.");

        } else if (Object.getPrototypeOf(constants) === Object.prototype && !Object.keys(constants).reduce(function (isObject, constant) {
                return Object.getPrototypeOf(constants[constant]) === Object.prototype;
            }, true)) {

            throw new TypeError("One or more constants do not have an associated object-value.");

        }

        var isArray = (constants instanceof Array);
        var isObject = !isArray;

        /** Private sentinel-object used to guard enum constructor so that no one else can create enum instances **/
        function __() { };

        /** Dynamically define a function with the same name as the enum we want to define. **/
        var __enum = new Function(["__"],
            "return function " + typeName + "(sentinel, name, ordinal) {" +
                "if(!(sentinel instanceof __)) {" +
                    "throw new TypeError(\"Cannot instantiate an instance of " + typeName + ".\");" +
                "}" +

                "this.__name = name;" +
                "this.__ordinal = ordinal;" +
            "}"
        )(__);

        /** Private objects used to maintain enum instances for values(), and to look up enum instances for fromName() **/
        var __values = [];
        var __dict = {};

        /** Attach values() and fromName() methods to the class itself (kind of like static methods). **/
        Object.defineProperty(__enum, "values", {
            value: function () {
                return __values;
            }
        });

        Object.defineProperty(__enum, "fromName", {
            value: function (name) {
                var __constant = __dict[name]
                if (__constant) {
                    return __constant;
                } else {
                    throw new TypeError(typeName + " does not have a constant with name " + name + ".");
                }
            }
        });

        /**
         * The following methods are available to all instances of the enum. values() and fromName() need to be
         * available to each constant, and so we will attach them on the prototype. But really, they're just
         * aliases to their counterparts on the prototype.
         */
        Object.defineProperty(__enum.prototype, "values", {
            value: __enum.values
        });

        Object.defineProperty(__enum.prototype, "fromName", {
            value: __enum.fromName
        });

        Object.defineProperty(__enum.prototype, "name", {
            value: function () {
                return this.__name;
            }
        });

        Object.defineProperty(__enum.prototype, "ordinal", {
            value: function () {
                return this.__ordinal;
            }
        });

        Object.defineProperty(__enum.prototype, "valueOf", {
            value: function () {
                return this.__name;
            }
        });

        Object.defineProperty(__enum.prototype, "toString", {
            value: function () {
                return this.__name;
            }
        });

        /**
         * If constants was an array, we can the element values directly. Otherwise, we will have to use the keys
         * from the constants object.
         */
        var _constants = constants;
        if (isObject) {
            _constants = Object.keys(constants);
        }

        /** Iterate over all constants, create an instance of our enum for each one, and attach it to the enum type **/
        _constants.forEach(function (name, ordinal) {
            // Create an instance of the enum
            var __constant = new __enum(new __(), name, ordinal);

            // If constants was an object, we want to attach the provided attributes to the instance.
            if (isObject) {
                Object.keys(constants[name]).forEach(function (attr) {
                    Object.defineProperty(__constant, attr, {
                        value: constants[name][attr]
                    });
                });
            }

            // Freeze the instance so that it cannot be modified.
            Object.freeze(__constant);

            // Attach the instance using the provided name to the enum type itself.
            Object.defineProperty(__enum, name, {
                value: __constant
            });

            // Update our private objects
            __values.push(__constant);
            __dict[name] = __constant;
        });

        /** Define a friendly toString method for the enum **/
        var string = typeName + " { " + __enum.values().map(function (c) {
                return c.name();
            }).join(", ") + " } ";

        Object.defineProperty(__enum, "toString", {
            value: function () {
                return string;
            }
        });

        /** Freeze our private objects **/
        Object.freeze(__values);
        Object.freeze(__dict);

        /** Freeze the prototype on the enum and the enum itself **/
        Object.freeze(__enum.prototype);
        Object.freeze(__enum);

        /** Return the enum **/
        return __enum;
    }

    return {
        define: define
    }

})();
4
répondu Vivin Paliath 2015-09-18 22:11:20

même si seules les méthodes statiques (et non les propriétés statiques) sont supportées dans ES2015 (voir ici aussi, §15.2.2.2), curieusement vous pouvez utiliser ce qui suit avec Babel avec le es2015 preset:

class CellState {
    v: string;
    constructor(v: string) {
        this.v = v;
        Object.freeze(this);
    }
    static EMPTY       = new CellState('e');
    static OCCUPIED    = new CellState('o');
    static HIGHLIGHTED = new CellState('h');
    static values      = function(): Array<CellState> {
        const rv = [];
        rv.push(CellState.EMPTY);
        rv.push(CellState.OCCUPIED);
        rv.push(CellState.HIGHLIGHTED);
        return rv;
    }
}
Object.freeze(CellState);

j'ai trouvé que cela fonctionnait comme prévu même entre les modules (par exemple importer le CellState enum à partir d'un autre module) et aussi lorsque j'importe un module en utilisant Webpack.

l'avantage de cette méthode par rapport à la plupart des autres réponses est que vous pouvez l'utiliser avec un vérificateur de type statique (par exemple Flow ) et vous pouvez affirmer, au moment du développement en utilisant le contrôle de type statique, que vos variables, paramètres, etc. sont du CellState "enum" spécifique plutôt que d'un autre enum (qui serait impossible de distinguer si vous avez utilisé des objets génériques ou des symboles).

mise à jour

Le code ci-dessus présente une lacune en ce qu'il permet de créer des objets supplémentaires de type CellState (même si on ne peut pas les affecter aux champs statiques de CellState puisqu'il est gelé). Néanmoins, le code plus raffiné ci-dessous offre les avantages suivants:

  1. pas plus d'objets de type CellState peut être créé
  2. vous êtes garanti qu'aucune deux instances enum ne se voient attribuer le même code
  3. utilitaire méthode pour récupérer l'enum d'une représentation de chaîne
  4. la fonction values qui renvoie toutes les instances de l'enum n'a pas à créer la valeur de retour de la manière décrite ci-dessus, manuelle (et sujette aux erreurs).

    'use strict';
    
    class Status {
    
    constructor(code, displayName = code) {
        if (Status.INSTANCES.has(code))
            throw new Error(`duplicate code value: [${code}]`);
        if (!Status.canCreateMoreInstances)
            throw new Error(`attempt to call constructor(${code}`+
           `, ${displayName}) after all static instances have been created`);
        this.code        = code;
        this.displayName = displayName;
        Object.freeze(this);
        Status.INSTANCES.set(this.code, this);
    }
    
    toString() {
        return `[code: ${this.code}, displayName: ${this.displayName}]`;
    }
    static INSTANCES   = new Map();
    static canCreateMoreInstances      = true;
    
    // the values:
    static ARCHIVED    = new Status('Archived');
    static OBSERVED    = new Status('Observed');
    static SCHEDULED   = new Status('Scheduled');
    static UNOBSERVED  = new Status('Unobserved');
    static UNTRIGGERED = new Status('Untriggered');
    
    static values      = function() {
        return Array.from(Status.INSTANCES.values());
    }
    
    static fromCode(code) {
        if (!Status.INSTANCES.has(code))
            throw new Error(`unknown code: ${code}`);
        else
            return Status.INSTANCES.get(code);
    }
    }
    
    Status.canCreateMoreInstances = false;
    Object.freeze(Status);
    exports.Status = Status;
    
4
répondu Marcus Junius Brutus 2016-12-23 22:38:00

Comme de l'écriture, octobre 2014 - donc, ici, est une solution moderne. J'écris la solution comme un module de noeud, et ont inclus un test en utilisant Mocha et Chai, ainsi que des underlorejs. Vous pouvez facilement les ignorer, et simplement prendre le code Enum si préféré.

vu beaucoup de messages avec des bibliothèques trop alambiquées etc. La solution pour obtenir le support enum en Javascript est tellement simple qu'elle n'est pas vraiment nécessaire. Voici le code:

fichier: enums.js

_ = require('underscore');

var _Enum = function () {

   var keys = _.map(arguments, function (value) {
      return value;
   });
   var self = {
      keys: keys
   };
   for (var i = 0; i < arguments.length; i++) {
      self[keys[i]] = i;
   }
   return self;
};

var fileFormatEnum = Object.freeze(_Enum('CSV', 'TSV'));
var encodingEnum = Object.freeze(_Enum('UTF8', 'SHIFT_JIS'));

exports.fileFormatEnum = fileFormatEnum;
exports.encodingEnum = encodingEnum;

Et un test pour illustrer ce qu'il vous donne:

fichier: enumsSpec.js

var chai = require("chai"),
    assert = chai.assert,
    expect = chai.expect,
    should = chai.should(),
    enums = require('./enums'),
    _ = require('underscore');


describe('enums', function () {

    describe('fileFormatEnum', function () {
        it('should return expected fileFormat enum declarations', function () {
            var fileFormatEnum = enums.fileFormatEnum;
            should.exist(fileFormatEnum);
            assert('{"keys":["CSV","TSV"],"CSV":0,"TSV":1}' === JSON.stringify(fileFormatEnum), 'Unexpected format');
            assert('["CSV","TSV"]' === JSON.stringify(fileFormatEnum.keys), 'Unexpected keys format');
        });
    });

    describe('encodingEnum', function () {
        it('should return expected encoding enum declarations', function () {
            var encodingEnum = enums.encodingEnum;
            should.exist(encodingEnum);
            assert('{"keys":["UTF8","SHIFT_JIS"],"UTF8":0,"SHIFT_JIS":1}' === JSON.stringify(encodingEnum), 'Unexpected format');
            assert('["UTF8","SHIFT_JIS"]' === JSON.stringify(encodingEnum.keys), 'Unexpected keys format');
        });
    });

});

comme vous pouvez le voir, vous obtenez une usine Enum, vous pouvez obtenir toutes les clés simplement en appelant enum.clés, et vous pouvez faire correspondre les touches elles-mêmes à des constantes entières. Et vous pouvez réutiliser l'usine avec des valeurs différentes, et exporter ces Énums générés en utilisant L'approche modulaire de Node.

encore une fois, si vous n'êtes qu'un utilisateur occasionnel, ou dans le navigateur, etc, il suffit de prendre la partie usine du code, éventuellement supprimer la bibliothèque de underscore aussi si vous ne souhaitez pas l'utiliser dans votre code.

3
répondu arcseldon 2014-11-20 17:44:48
var ColorEnum = {
    red: {},
    green: {},
    blue: {}
}

vous n'avez pas besoin de vous assurer que vous n'assignez pas des numéros dupliqués à des valeurs enum différentes de cette façon. Un nouvel objet est instancié et assigné à toutes les valeurs enum.

3
répondu Shivanshu Goyal 2015-01-29 01:32:23

Vous pouvez faire quelque chose comme cela

function Enum(){
  this.add.apply(this,arguments);
}

Enum.prototype.add = function(){
  for (var i in arguments) {
    this[arguments[i]] = new String(arguments[i]);
  }
};
Enum.prototype.toList = function(){
  return Object.keys(this)
};

var STATUS = new Enum("CLOSED","PENDING");


var STATE = new Enum("CLOSED","PENDING");

STATE.CLOSED === STATUS.CLOSED  // false;
STATE.CLOSED === "CLOSED"  // false;
STATE.CLOSED.toString() === "CLOSED"  // true;

comme défini dans cette bibliothèque. https://github.com/webmodule/foo/blob/master/foo.js#L217

3
répondu LNT 2016-05-25 06:32:25

solution la plus simple:

créer

var Status = Object.freeze({
    "Connecting":0,
    "Ready":1,
    "Loading":2,
    "Processing": 3
});

Obtenir La Valeur

console.log(Status.Ready) // 1

La Clé

console.log(Object.keys(Status)[Status.Ready]) // Ready
3
répondu Ilya Gazman 2016-08-17 12:38:45

C'est comme ça que Typescript traduit enum en Javascript:

var makeEnum = function(obj) {
    obj[ obj['Active'] = 1 ] = 'Active';
    obj[ obj['Closed'] = 2 ] = 'Closed';
    obj[ obj['Deleted'] = 3 ] = 'Deleted';
}

Maintenant:

makeEnum( NewObj = {} )
// => {1: "Active", 2: "Closed", 3: "Deleted", Active: 1, Closed: 2, Deleted: 3}

d'abord j'ai été confus pourquoi obj[1] retourne 'Active' , mais ensuite j'ai réalisé que son simple mort - opérateur D'affectation assigne la valeur, puis la renvoie:

obj['foo'] = 1
// => 1
3
répondu Julius Dzidzevičius 2018-05-03 18:44:59

Je l'avais fait il y a un certain temps en utilisant un mélange de __defineGetter__ et __defineSetter__ ou defineProperty selon la version JS.

Voici la fonction génératrice enum que j'ai créée: https://gist.github.com/gfarrell/6716853

vous l'utilisez comme ceci:

var Colours = Enum('RED', 'GREEN', 'BLUE');

et il créerait une chaîne immuable:dictionnaire int (an enum).

2
répondu GTF 2013-09-26 17:04:01

c'est facile à utiliser, je pense. https://stackoverflow.com/a/32245370/4365315

var A = {a:11, b:22}, 
enumA = new TypeHelper(A);

if(enumA.Value === A.b || enumA.Key === "a"){ 
... 
}

var keys = enumA.getAsList();//[object, object]

//set
enumA.setType(22, false);//setType(val, isKey)

enumA.setType("a", true);

enumA.setTypeByIndex(1);

mise à jour:

il y a mes codes d'aide ( TypeHelper ).

var Helper = {
    isEmpty: function (obj) {
        return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
    },

    isObject: function (obj) {
        return (typeof obj === 'object');
    },

    sortObjectKeys: function (object) {
        return Object.keys(object)
            .sort(function (a, b) {
                c = a - b;
                return c
            });
    },
    containsItem: function (arr, item) {
        if (arr && Array.isArray(arr)) {
            return arr.indexOf(item) > -1;
        } else {
            return arr === item;
        }
    },

    pushArray: function (arr1, arr2) {
        if (arr1 && arr2 && Array.isArray(arr1)) {
            arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
        }
    }
};
function TypeHelper() {
    var _types = arguments[0],
        _defTypeIndex = 0,
        _currentType,
        _value,
        _allKeys = Helper.sortObjectKeys(_types);

    if (arguments.length == 2) {
        _defTypeIndex = arguments[1];
    }

    Object.defineProperties(this, {
        Key: {
            get: function () {
                return _currentType;
            },
            set: function (val) {
                _currentType.setType(val, true);
            },
            enumerable: true
        },
        Value: {
            get: function () {
                return _types[_currentType];
            },
            set: function (val) {
                _value.setType(val, false);
            },
            enumerable: true
        }
    });
    this.getAsList = function (keys) {
        var list = [];
        _allKeys.forEach(function (key, idx, array) {
            if (key && _types[key]) {

                if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) {
                    var json = {};
                    json.Key = key;
                    json.Value = _types[key];
                    Helper.pushArray(list, json);
                }
            }
        });
        return list;
    };

    this.setType = function (value, isKey) {
        if (!Helper.isEmpty(value)) {
            Object.keys(_types).forEach(function (key, idx, array) {
                if (Helper.isObject(value)) {
                    if (value && value.Key == key) {
                        _currentType = key;
                    }
                } else if (isKey) {
                    if (value && value.toString() == key.toString()) {
                        _currentType = key;
                    }
                } else if (value && value.toString() == _types[key]) {
                    _currentType = key;
                }
            });
        } else {
            this.setDefaultType();
        }
        return isKey ? _types[_currentType] : _currentType;
    };

    this.setTypeByIndex = function (index) {
        for (var i = 0; i < _allKeys.length; i++) {
            if (index === i) {
                _currentType = _allKeys[index];
                break;
            }
        }
    };

    this.setDefaultType = function () {
        this.setTypeByIndex(_defTypeIndex);
    };

    this.setDefaultType();
}

var TypeA = {
    "-1": "Any",
    "2": "2L",
    "100": "100L",
    "200": "200L",
    "1000": "1000L"
};

var enumA = new TypeHelper(TypeA, 4);

document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setType("200L", false);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

enumA.setDefaultType();
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setTypeByIndex(1);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

document.writeln("is equals = ", (enumA.Value == TypeA["2"]));
2
répondu Sherali Turdiyev 2017-05-23 11:47:32