Какой синтаксис является предпочтительным для определения перечислений в JavaScript? [закрыто]

Какой синтаксис является предпочтительным для определения перечислений в JavaScript? Что-то вроде:

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

// later on

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

Или есть более предпочтительная идиома?

1918
задан DAIRAV 26 December 2018 в 06:38
поделиться

43 ответа

Начиная с 1.8.5, можно запечатать и заморозить объект, поэтому определите вышеизложенное как:

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

или

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

и вуаля! JS перечисляет.

Примечание: я написал это в 2011 году, но это 2019 - используйте const для предотвращения перезаписи вашего словаря enum.

Тем не менее, это не мешает вам присвоить нежелательное значение переменной, что часто является главной целью перечислений:

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

Один из способов обеспечить более высокую степень безопасности типов (с перечисления или иным образом) использовать такой инструмент, как TypeScript или Flow .

Источник

Цитаты не нужны, но я сохранил их для согласованности.

747
ответ дан Artur Czajka 26 December 2018 в 06:38
поделиться

Быстрый и простой способ будет:

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

console.log(Colors.WHITE)  //this prints out "0"
3
ответ дан user2254487 26 December 2018 в 06:38
поделиться

Я написал enumerationjs a очень крошечную библиотеку для решения проблемы , которая обеспечивает безопасность типов , позволяет константе enum наследоваться от прототипа ], гарантирует, что константы и типы перечислений будут неизменными + множество мелких особенностей. Это позволяет проводить рефакторинг большого количества кода и перемещать некоторую логику в определение перечисления. Вот пример:

var CloseEventCodes = new Enumeration("closeEventCodes", {
  CLOSE_NORMAL:          { _id: 1000, info: "Connection closed normally" },
  CLOSE_GOING_AWAY:      { _id: 1001, info: "Connection closed going away" },
  CLOSE_PROTOCOL_ERROR:  { _id: 1002, info: "Connection closed due to protocol error"  },
  CLOSE_UNSUPPORTED:     { _id: 1003, info: "Connection closed due to unsupported operation" },
  CLOSE_NO_STATUS:       { _id: 1005, info: "Connection closed with no status" },
  CLOSE_ABNORMAL:        { _id: 1006, info: "Connection closed abnormally" },
  CLOSE_TOO_LARGE:       { _id: 1009, info: "Connection closed due to too large packet" }
},{ talk: function(){
    console.log(this.info); 
  }
});


CloseEventCodes.CLOSE_TOO_LARGE.talk(); //prints "Connection closed due to too large packet"
CloseEventCodes.CLOSE_TOO_LARGE instanceof CloseEventCodes //evaluates to true

Enumeration в основном фабрика.

Полностью документированное руководство доступно здесь. Надеюсь это поможет.

3
ответ дан Jules Randolph 26 December 2018 в 06:38
поделиться

Вы также можете попытаться определить новую функцию и, следовательно, новое пространство имен и добавить к ней переменные, например, так.

function Color () {};  
Color.RED = 1;
Color.YELLOW = 2;

Пока кто-нибудь использует пространство имен, предоставляемое функцией Color, все будет хорошо. Если вы знаете Java, это своего рода старые перечисления: где мы используем класс или интерфейс только для хранения статических атрибутов. Если функция в javascript является своего рода классом, то это почти такой же подход.

Я думаю, что это очень простой способ определить перечисления.

Надеюсь, это поможет!

Привет.

Виктор.

-1
ответ дан Victor 26 December 2018 в 06:38
поделиться

Вы можете попробовать использовать https://bitbucket.org/snippets/frostbane/aAjxM .

my.namespace.ColorEnum = new Enum(
    "RED = 0",
    "GREEN",
    "BLUE"
)

Это должно работать до ie8.

-1
ответ дан mika 26 December 2018 в 06:38
поделиться

Вы можете сделать что-то вроде этого

    var Enum = (function(foo) {

    var EnumItem = function(item){
        if(typeof item == "string"){
            this.name = item;
        } else {
            this.name = item.name;
        }
    }
    EnumItem.prototype = new String("DEFAULT");
    EnumItem.prototype.toString = function(){
        return this.name;
    }
    EnumItem.prototype.equals = function(item){
        if(typeof item == "string"){
            return this.name == item;
        } else {
            return this == item && this.name == item.name;
        }
    }

    function Enum() {
        this.add.apply(this, arguments);
        Object.freeze(this);
    }
    Enum.prototype.add = function() {
        for (var i in arguments) {
            var enumItem = new EnumItem(arguments[i]);
            this[enumItem.name] = enumItem;
        }
    };
    Enum.prototype.toList = function() {
        return Object.keys(this);
    };
    foo.Enum = Enum;
    return Enum;
})(this);
var STATUS = new Enum("CLOSED","PENDING", { name : "CONFIRMED", ackd : true });
var STATE = new Enum("CLOSED","PENDING","CONFIRMED",{ name : "STARTED"},{ name : "PROCESSING"});

Как определено в этой библиотеке. https://github.com/webmodule/foo/blob/master/foo.js#L217

Полный пример https://gist.github.com/lnt/ bb13a2fd63cdb8bce85fd62965a20026

4
ответ дан LNT 26 December 2018 в 06:38
поделиться

В ES7 вы можете сделать элегантный ENUM, опираясь на статические атрибуты:

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

, затем

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

Преимущество (использование класса вместо литеральный объект) должен иметь родительский класс Enum, тогда все ваши Enums будут расширять этот класс.

 class ColorEnum  extends Enum {/*....*/}
15
ответ дан Abdennour TOUMI 26 December 2018 в 06:38
поделиться

Вот что мы все хотим:

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

Теперь вы можете создавать свои перечисления:

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

Таким образом, к константам можно обращаться обычным способом (Да Нет. ДА , Color.GREEN) и они получают последовательное значение типа int (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

Вы также можете добавить методы, используя 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 */
};


Редактировать - небольшое улучшение - теперь с varargs: (к сожалению, это не работает должным образом в IE: S ... следует придерживаться предыдущей версии)

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

var YesNo = new Enum('NO', 'YES');
var Color = new Enum('RED', 'GREEN', 'BLUE');
55
ответ дан Andre 'Fi' 26 December 2018 в 06:38
поделиться

Итог: нельзя.

Вы можете подделать это, но вы не получите безопасность типа. Обычно это делается путем создания простого словаря строковых значений, сопоставленных с целочисленными значениями. Например:

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

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

Проблема с этим подходом? Вы можете случайно переопределить свой перечислитель или случайно иметь повторяющиеся значения перечислителя. Например:

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

Редактировать

Как насчет Object.freeze Артура Чайка? Разве это не сработает, чтобы помешать вам установить понедельник на четверг? - Фрай Квад

Абсолютно, Object.freeze полностью решит проблему, на которую я жаловался. Я хотел бы напомнить всем, что, когда я писал выше, Object.freeze действительно не существовало.

Теперь ... теперь это открывает некоторые очень интересные возможности.

Редактировать 2
Вот очень хорошая библиотека для создания перечислений.

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

Хотя это, вероятно, не подходит для каждого допустимого использования перечислений, оно идет очень долгий путь

80
ответ дан Randolpho 26 December 2018 в 06:38
поделиться

Вы можете использовать Object.prototype.hasOwnProperty ()

var findInEnum,
    colorEnum = {
    red : 0,
    green : 1,
    blue : 2
};

// later on

findInEnum = function (enumKey) {
  if (colorEnum.hasOwnProperty(enumKey)) {
    return enumKey+' Value: ' + colorEnum[enumKey]
  }
}

alert(findInEnum("blue"))
1
ответ дан Pang 26 December 2018 в 06:38
поделиться
var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });

Вам не нужно указывать идентификатор , вы можете просто использовать пустой объект для сравнения перечислений.

if (incommingEnum === DaysEnum.monday) //incommingEnum is monday

РЕДАКТИРОВАТЬ: Если вы собираетесь сериализовать объект (например, в JSON), вы снова получите id .

0
ответ дан Community 26 December 2018 в 06:38
поделиться

Я играл с этим, потому что я люблю свои перечисления. =)

Используя Object.defineProperty, я думаю, что нашел несколько жизнеспособное решение.

Вот jsfiddle: http://jsfiddle.net/ZV4A6/

Используя этот метод ... вы должны (в теории) иметь возможность вызывать и определять значения перечисления для любого объект, не затрагивая другие атрибуты этого объекта.

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

Из-за атрибута writable:false этот должен сделать его тип безопасным.

Таким образом, вы сможете создать пользовательский объект, а затем вызвать Enum() для него. Назначенные значения начинаются с 0 и увеличиваются на единицу.

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3
22
ответ дан Duncan 26 December 2018 в 06:38
поделиться

es7 way, (iterator, freeze), использование:

const ThreeWiseMen = new Enum('Melchior', 'Caspar', 'Balthazar')

for (let name of ThreeWiseMen)
    console.log(name)


// with a given key
let key = ThreeWiseMen.Melchior

console.log(key in ThreeWiseMen) // true (string conversion, also true: 'Melchior' in ThreeWiseMen)

for (let entry from key.enum)
     console.log(entry)


// prevent alteration (throws TypeError in strict mode)
ThreeWiseMen.Me = 'Me too!'
ThreeWiseMen.Melchior.name = 'Foo'

код:

class EnumKey {

    constructor(props) { Object.freeze(Object.assign(this, props)) }

    toString() { return this.name }

}

export class Enum {

    constructor(...keys) {

        for (let [index, key] of keys.entries()) {

            Object.defineProperty(this, key, {

                value: new EnumKey({ name:key, index, enum:this }),
                enumerable: true,

            })

        }

        Object.freeze(this)

    }

    *[Symbol.iterator]() {

        for (let key of Object.keys(this))
            yield this[key]

    }

    toString() { return [...this].join(', ') }

}
4
ответ дан Joseph Merdrignac 26 December 2018 в 06:38
поделиться

Это решение, которое я использую.

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

И вы определяете свои перечисления следующим образом:

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

И вот как вы получаете доступ к своим перечислениям:

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

Я обычно использую последние 2 метода для отображения перечисления из объектов сообщений.

Некоторые преимущества этого подхода:

  • Легко объявлять перечисления
  • Легко получить доступ к вашим перечислениям
  • Ваши перечисления могут быть сложных типов
  • У класса Enum есть некоторое ассоциативное кеширование, если вы часто используете getByValue

Некоторые недостатки:

  • Некоторое грязное управление памятью происходит там, так как я держу ссылки перечисления
  • Все еще нет безопасности типа
14
ответ дан Chris 26 December 2018 в 06:38
поделиться

ваши ответы слишком сложны

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
8
ответ дан Xeltor 26 December 2018 в 06:38
поделиться

Создать литерал объекта:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};
14
ответ дан hvdd 26 December 2018 в 06:38
поделиться

В большинстве современных браузеров существует примитивный тип данных символа , который можно использовать для создания перечисления. Это обеспечит безопасность типов перечисления, так как каждое значение символа гарантировано JavaScript уникальным, т.е. Symbol() != Symbol(). Например:

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

Чтобы упростить отладку, вы можете добавить описание к значениям перечисления:

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

Демо Plunker

Вкл GitHub вы можете найти оболочку, которая упрощает код, необходимый для инициализации перечисления:

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
47
ответ дан YakovL 26 December 2018 в 06:38
поделиться

Это старая версия, которую я знаю, но с тех пор она была реализована с помощью интерфейса TypeScript:

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

Это позволяет вам посмотреть на MyEnum.Bar, который возвращает 1, и MyEnum[1], который возвращает "Bar" независимо от порядка объявления.

17
ответ дан Rob Hardy 26 December 2018 в 06:38
поделиться

Я изменил решение Андре '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);
    }
  }

Тест:

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
7
ответ дан David Miró 26 December 2018 в 06:38
поделиться

Несмотря на то, что только статические методы (а не статические свойства) поддерживаются в ES2015 (см. Также здесь и раздел 15.2.2.2), любопытно, что вы можете использовать ниже с Вавилон с предустановкой es2015:

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

Я обнаружил, что это работает должным образом даже между модулями (например, импорт перечисления CellState из другого модуля), а также при импорте модуля с помощью Webpack.

Преимущество этого метода перед большинством других ответов заключается в том, что вы можете использовать его вместе со средством проверки статического типа (например, Flow ), и вы можете утверждать, во время разработки, используя статический тип проверка того, что ваши переменные, параметры и т. д. относятся к определенному CellState «перечислению», а не к какому-либо другому перечислению (которое было бы невозможно отличить, если вы использовали общие объекты или символы).

update

Приведенный выше код имеет недостаток в том, что он позволяет создавать дополнительные объекты типа CellState (даже если нельзя назначить их статическим полям CellState, поскольку он заморожен). ). Тем не менее, приведенный ниже более усовершенствованный код предлагает следующие преимущества:

  1. больше нельзя создавать объекты типа CellState
  2. вам гарантировано, что никакие два экземпляра enum не будут назначены одинаково Утилита code
  3. для получения перечисления из строкового представления.
  4. функция values, которая возвращает все экземпляры перечисления, не должна создавать возвращаемое значение в приведенном выше примере. , ручной (и подверженный ошибкам) ​​способ.

    '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
ответ дан Marcus Junius Brutus 26 December 2018 в 06:38
поделиться

Решение Alien состоит в том, чтобы сделать вещи максимально простыми:

  1. использовать ключевое слово enum (зарезервировано в javascript)
  2. Если ключевое слово enum зарезервировано, но не реализовано в вашем javascript определите следующее

    const enumerate = spec => spec.split(/\s*,\s*/)
      .reduce((e, n) => Object.assign(e,{[n]:n}), {}) 
    

Теперь вы можете легко использовать его

const kwords = enumerate("begin,end, procedure,if")
console.log(kwords, kwords.if, kwords.if == "if", kwords.undef)

Я не вижу причин делать значения перечисления явными переменными. Сценарии в любом случае являются морфизированными, и не имеет значения, является ли часть вашего кода строкой или допустимым кодом. Что действительно важно, так это то, что вам не нужно иметь дело с тоннами кавычек при их использовании или определении.

1
ответ дан Little Alien 26 December 2018 в 06:38
поделиться
class Enum {
  constructor (...vals) {
    vals.forEach( val => {
      const CONSTANT = Symbol(val);
      Object.defineProperty(this, val.toUpperCase(), {
        get () {
          return CONSTANT;
        },
        set (val) {
          const enum_val = "CONSTANT";
          // generate TypeError associated with attempting to change the value of a constant
          enum_val = val;
        }
      });
    });
  }
}

Пример использования:

const COLORS = new Enum("red", "blue", "green");
1
ответ дан papiro 26 December 2018 в 06:38
поделиться

Если вы используете Backbone , вы можете бесплатно получить полнофункциональную функцию enum (поиск по идентификатору, имени, пользовательским элементам), используя 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()
11
ответ дан Yaroslav 26 December 2018 в 06:38
поделиться

Вот пара различных способов реализации перечислений TypeScript .

Самый простой способ - просто перебрать объект, добавив к нему инвертированные пары ключ-значение. Единственным недостатком является то, что вы должны вручную установить значение для каждого члена.

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


А вот lodash mixin для создания перечисления с использованием строки. Хотя эта версия немного сложнее, она выполняет нумерацию автоматически. Все методы lodash, используемые в этом примере, имеют обычный JavaScript-эквивалент, поэтому вы можете легко их отключить, если хотите.

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
ответ дан Blake Bowen 26 December 2018 в 06:38
поделиться

Прочитал все ответы и не нашел ни одного многословного и СУХОГО решения. Я использую этот однострочник:

const modes = ['DRAW', 'SCALE', 'DRAG'].reduce((o, v) => ({ ...o, [v]: v }), {});

он генерирует объект с понятными для человека значениями:

{
  DRAW: 'DRAW',
  SCALE: 'SCALE',
  DRAG: 'DRAG'
}
1
ответ дан oluckyman 26 December 2018 в 06:38
поделиться

Я создал класс Enum, который может извлекать значения И имена в O (1). Он также может генерировать массив объектов, содержащий все имена и значения.

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

Вы можете инициировать это так:

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

Чтобы получить значение (например, перечисления в C #):

var val2 = enum1.item2;

Чтобы получить имя для значение (может быть неоднозначным при установке одного и того же значения для разных имен):

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

Чтобы получить массив с каждым именем & amp; значение в объекте:

var arr = enum1.GetObjArr();

Сгенерирует:

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

Вы также можете легко получить html-параметры выбора:

var html = enum1.GetSelectOptionsHTML();

Что содержит:

"<option value='0'>item1</option>..."
4
ответ дан Tim Kara 26 December 2018 в 06:38
поделиться

Это не очень хороший ответ, но я бы сказал, что он работает очень хорошо, лично

Сказав это, поскольку значения не имеют (вы использовали 0, 1, 2), я бы использовал значимую строку на тот случай, если вы захотите вывести текущее значение.

594
ответ дан Gareth 26 December 2018 в 06:38
поделиться

Вы можете попробовать это:

   var Enum = Object.freeze({
            Role: Object.freeze({ Administrator: 1, Manager: 2, Supervisor: 3 }),
            Color:Object.freeze({RED : 0, GREEN : 1, BLUE : 2 })
            });

    alert(Enum.Role.Supervisor);
    alert(Enum.Color.GREEN);
    var currentColor=0;
    if(currentColor == Enum.Color.RED) {
       alert('Its Red');
    }
2
ответ дан Muhammad Awais 26 December 2018 в 06:38
поделиться

Очень похоже на то, что делал @Duncan выше, но мне не нравится запутывать глобальное пространство функций объекта с помощью Enum, поэтому я написал следующее:

function mkenum_1()
{
  var o = new Object();
  var c = -1;
  var f = function(e, v) { Object.defineProperty(o, e, { value:v, writable:false, enumerable:true, configurable:true })};

  for (i in arguments) {
    var e = arguments[i];
    if ((!!e) & (e.constructor == Object))
      for (j in e)
        f(j, (c=e[j]));
    else
      f(e, ++c);
    }

  return Object.freeze ? Object.freeze(o) : o;
}

var Sizes = mkenum_1('SMALL','MEDIUM',{LARGE: 100},'XLARGE');

console.log("MED := " + Sizes.MEDIUM);
console.log("LRG := " + Sizes.LARGE);

// Output is:
// MED := 1
// LRG := 100

@Stijin также имеет аккуратное решение (ссылаясь на в его блог), который включает в себя свойства этих объектов. Я тоже написал для этого код, который я включаю в следующий.

function mkenum_2(seed)
{
    var p = {};

    console.log("Seed := " + seed);

    for (k in seed) {
        var v = seed[k];

        if (v instanceof Array)
            p[(seed[k]=v[0])] = { value: v[0], name: v[1], code: v[2] };
        else
            p[v] = { value: v, name: k.toLowerCase(), code: k.substring(0,1) };
    }
    seed.properties = p;

    return Object.freeze ? Object.freeze(seed) : seed;
}

Эта версия создает дополнительный список свойств, позволяющий удобное преобразование имен и короткие коды. Мне нравится эта версия, потому что не нужно дублировать ввод данных в свойствах, поскольку код делает это за вас.

var SizeEnum2 = mkenum_2({ SMALL: 1, MEDIUM: 2, LARGE: 3});
var SizeEnum3 = mkenum_2({ SMALL: [1, "small", "S"], MEDIUM: [2, "medium", "M"], LARGE: [3, "large", "L"] });

Эти два могут быть объединены в один блок обработки, mkenum, (использовать перечисления, присваивать значения, создавать и добавлять список свойств). Однако, поскольку я уже потратил слишком много времени на это сегодня, я оставлю комбинацию в качестве упражнения для дорогого читателя.

1
ответ дан Andrew Philips 26 December 2018 в 06:38
поделиться

Я только что опубликовал пакет NPM gen_enum , позволяющий быстро создавать структуру данных Enum в 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 

Одна приятная вещь об этом небольшом инструменте - в современной среде ( включая nodejs и браузеры IE 9+) возвращаемый объект Enum является неизменным.

Для получения дополнительной информации, пожалуйста, проверьте https://github.com/greenlaw110/enumjs

Обновления

Я устарел gen_enum пакет и объединить функцию в пакет constjs , который предоставляет больше возможностей, включая неизменяемые объекты, десериализацию строк JSON, константы строк, генерацию растровых изображений и т. д. Оформить заказ https://www.npmjs.com/package/constjs для получения дополнительной информации

Чтобы перейти с gen_enum на constjs, просто измените оператор

var genEnum = require('gen_enum');

на

var genEnum = require('constjs').enum;
4
ответ дан Gelin Luo 26 December 2018 в 06:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: