23

Как гарантировать, что определение моих enum не изменится в JavaScript?

16

Вопрос: Выполняют ли следующие объекты все характеристики перечислений (enums) в JavaScript? Рассматриваю следующий код:

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

// далее

if(currentColor == my.namespace.ColorEnum.RED) { // какие-то действия }

Либо есть другой способ, как я могу это реализовать?

5 ответ(ов)

6

Это не совсем ответ, но, на мой взгляд, это вполне нормально.

Тем не менее, раз не имеет значения, какие значения вы используете (вы применили 0, 1, 2), я бы рекомендовал использовать содержительную строку на случай, если вам когда-либо нужно будет вывести текущее значение.

0

Вот что нам всем нужно:

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

Таким образом, константы могут быть доступны обычным способом (например, YesNo.YES, Color.GREEN), и им назначается последовательное целочисленное значение (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

Вы также можете добавлять методы, используя Enum.prototype:

Enum.prototype.values = function() {
    return this.allValues;
    /* чтобы это работало, нужно будет определить
            this.allValues = constantsList в конструкторе */
};

Редактирование - небольшое улучшение - теперь с переменным количеством аргументов: (к сожалению, это не работает должным образом в 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');

Если у вас есть дополнительные вопросы, не стесняйтесь задавать!

0

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

Используя 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

Если у вас есть вопросы или вы хотите обсудить это решение, не стесняйтесь обращаться!

0

Это старый вопрос, я знаю, но в 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", независимо от порядка объявления.

0

Вы можете создать объект-литерал в JavaScript, как показано в вашем примере. Вот как это выглядит:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};

Этот объект Modes содержит три свойства: DRAGGING, SCALING и CLICKED, каждое из которых имеет строковое значение. Вы можете использовать этот объект для управления режимами в вашей программе, обращаясь к его свойствам, например, Modes.DRAGGING для получения строки 'drag'.

Если вам нужно добавить новые режимы или изменить существующие, вы можете просто обновить объект, не меняя его структуру. Например:

Modes.ZOOMING = 'zoom';

Теперь Modes будет включать также режим ZOOMING с соответствующим значением 'zoom'.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь