Нравится это:
from c in db.Company
group c by c.Name into grp
where grp.Count() > 1
select grp.Key
Или, используя синтаксис метода:
Company
.GroupBy(c => c.Name)
.Where(grp => grp.Count() > 1)
.Select(grp => grp.Key);
Начиная с 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 .
Цитаты не нужны, но я сохранил их для согласованности.
Быстрый и простой способ будет:
var Colors = function(){
return {
'WHITE':0,
'BLACK':1,
'RED':2,
'GREEN':3
}
}();
console.log(Colors.WHITE) //this prints out "0"
Я написал 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
в основном фабрика.
Полностью документированное руководство доступно здесь. Надеюсь это поможет.
Вы также можете попытаться определить новую функцию и, следовательно, новое пространство имен и добавить к ней переменные, например, так.
function Color () {};
Color.RED = 1;
Color.YELLOW = 2;
Пока кто-нибудь использует пространство имен, предоставляемое функцией Color, все будет хорошо. Если вы знаете Java, это своего рода старые перечисления: где мы используем класс или интерфейс только для хранения статических атрибутов. Если функция в javascript является своего рода классом, то это почти такой же подход.
Я думаю, что это очень простой способ определить перечисления.
Надеюсь, это поможет!
Привет.
Виктор.
Вы можете попробовать использовать https://bitbucket.org/snippets/frostbane/aAjxM .
my.namespace.ColorEnum = new Enum(
"RED = 0",
"GREEN",
"BLUE"
)
Это должно работать до ie8.
Вы можете сделать что-то вроде этого
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
В ES7 вы можете сделать элегантный ENUM, опираясь на статические атрибуты:
class ColorEnum {
static RED = 0 ;
static GREEN = 1;
static BLUE = 2;
}
, затем
if (currentColor === ColorEnum.GREEN ) {/*-- coding --*/}
Преимущество (использование класса вместо литеральный объект) должен иметь родительский класс Enum
, тогда все ваши Enums будут расширять этот класс.
class ColorEnum extends Enum {/*....*/}
Вот что мы все хотим:
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');
Итог: нельзя.
Вы можете подделать это, но вы не получите безопасность типа. Обычно это делается путем создания простого словаря строковых значений, сопоставленных с целочисленными значениями. Например:
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
Хотя это, вероятно, не подходит для каждого допустимого использования перечислений, оно идет очень долгий путь
Вы можете использовать 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"))
var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });
Вам не нужно указывать идентификатор , вы можете просто использовать пустой объект для сравнения перечислений.
if (incommingEnum === DaysEnum.monday) //incommingEnum is monday
РЕДАКТИРОВАТЬ: Если вы собираетесь сериализовать объект (например, в JSON), вы снова получите id .
Я играл с этим, потому что я люблю свои перечисления. =)
Используя 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
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(', ') }
}
Это решение, которое я использую.
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 метода для отображения перечисления из объектов сообщений.
Некоторые преимущества этого подхода:
Некоторые недостатки:
ваши ответы слишком сложны
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
Создать литерал объекта:
const Modes = {
DRAGGING: 'drag',
SCALING: 'scale',
CLICKED: 'click'
};
В большинстве современных браузеров существует примитивный тип данных символа , который можно использовать для создания перечисления. Это обеспечит безопасность типов перечисления, так как каждое значение символа гарантировано JavaScript уникальным, т.е. Symbol() != Symbol()
. Например:
const COLOR = Object.freeze({RED: Symbol(), BLUE: Symbol()});
Чтобы упростить отладку, вы можете добавить описание к значениям перечисления:
const COLOR = Object.freeze({RED: Symbol("RED"), BLUE: Symbol("BLUE")});
Вкл 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
Это старая версия, которую я знаю, но с тех пор она была реализована с помощью интерфейса 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" независимо от порядка объявления.
Я изменил решение Андре '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
Несмотря на то, что только статические методы (а не статические свойства) поддерживаются в 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
«перечислению», а не к какому-либо другому перечислению (которое было бы невозможно отличить, если вы использовали общие объекты или символы).
Приведенный выше код имеет недостаток в том, что он позволяет создавать дополнительные объекты типа CellState
(даже если нельзя назначить их статическим полям CellState
, поскольку он заморожен). ). Тем не менее, приведенный ниже более усовершенствованный код предлагает следующие преимущества:
CellState
функция 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;
Решение Alien состоит в том, чтобы сделать вещи максимально простыми:
Если ключевое слово 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)
Я не вижу причин делать значения перечисления явными переменными. Сценарии в любом случае являются морфизированными, и не имеет значения, является ли часть вашего кода строкой или допустимым кодом. Что действительно важно, так это то, что вам не нужно иметь дело с тоннами кавычек при их использовании или определении.
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");
Если вы используете 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()
Вот пара различных способов реализации перечислений 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
Прочитал все ответы и не нашел ни одного многословного и СУХОГО решения. Я использую этот однострочник:
const modes = ['DRAW', 'SCALE', 'DRAG'].reduce((o, v) => ({ ...o, [v]: v }), {});
он генерирует объект с понятными для человека значениями:
{
DRAW: 'DRAW',
SCALE: 'SCALE',
DRAG: 'DRAG'
}
Я создал класс 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>..."
Это не очень хороший ответ, но я бы сказал, что он работает очень хорошо, лично
Сказав это, поскольку значения не имеют (вы использовали 0, 1, 2), я бы использовал значимую строку на тот случай, если вы захотите вывести текущее значение.
Вы можете попробовать это:
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');
}
Очень похоже на то, что делал @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, (использовать перечисления, присваивать значения, создавать и добавлять список свойств). Однако, поскольку я уже потратил слишком много времени на это сегодня, я оставлю комбинацию в качестве упражнения для дорогого читателя.
Я только что опубликовал пакет 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;