Here is my implementation of a Java enumeration in JavaScript.
I also included unit tests.
const main = () => {
mocha.setup('bdd')
chai.should()
describe('Test Color [From Array]', function() {
let Color = new Enum('RED', 'BLUE', 'GREEN')
it('Test: Color.values()', () => {
Color.values().length.should.equal(3)
})
it('Test: Color.RED', () => {
chai.assert.isNotNull(Color.RED)
})
it('Test: Color.BLUE', () => {
chai.assert.isNotNull(Color.BLUE)
})
it('Test: Color.GREEN', () => {
chai.assert.isNotNull(Color.GREEN)
})
it('Test: Color.YELLOW', () => {
chai.assert.isUndefined(Color.YELLOW)
})
})
describe('Test Color [From Object]', function() {
let Color = new Enum({
RED : { hex: '#F00' },
BLUE : { hex: '#0F0' },
GREEN : { hex: '#00F' }
})
it('Test: Color.values()', () => {
Color.values().length.should.equal(3)
})
it('Test: Color.RED', () => {
let red = Color.RED
chai.assert.isNotNull(red)
red.getHex().should.equal('#F00')
})
it('Test: Color.BLUE', () => {
let blue = Color.BLUE
chai.assert.isNotNull(blue)
blue.getHex().should.equal('#0F0')
})
it('Test: Color.GREEN', () => {
let green = Color.GREEN
chai.assert.isNotNull(green)
green.getHex().should.equal('#00F')
})
it('Test: Color.YELLOW', () => {
let yellow = Color.YELLOW
chai.assert.isUndefined(yellow)
})
})
mocha.run()
}
class Enum {
constructor(values) {
this.__values = []
let isObject = arguments.length === 1
let args = isObject ? Object.keys(values) : [...arguments]
args.forEach((name, index) => {
this.__createValue(name, isObject ? values[name] : null, index)
})
Object.freeze(this)
}
values() {
return this.__values
}
/* @private */
__createValue(name, props, index) {
let value = new Object()
value.__defineGetter__('name', function() {
return Symbol(name)
})
value.__defineGetter__('ordinal', function() {
return index
})
if (props) {
Object.keys(props).forEach(prop => {
value.__defineGetter__(prop, function() {
return props[prop]
})
value.__proto__['get' + this.__capitalize(prop)] = function() {
return this[prop]
}
})
}
Object.defineProperty(this, name, {
value: Object.freeze(value),
writable: false
})
this.__values.push(this[name])
}
/* @private */
__capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
}
main()
_x000D_
.as-console-wrapper { top: 0; max-height: 100% !important; }
_x000D_
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.2.0/chai.js"></script>
<!--
public enum Color {
RED("#F00"),
BLUE("#0F0"),
GREEN("#00F");
private String hex;
public String getHex() { return this.hex; }
private Color(String hex) {
this.hex = hex;
}
}
-->
<div id="mocha"></div>
_x000D_
Here is a more up-to-date version that satisfies MDN.
The Object.prototype.__defineGetter__
has been replaced by Object.defineProperty
per MDN's recomendation:
This feature is deprecated in favor of defining getters using the object initializer syntax or the
Object.defineProperty()
API. While this feature is widely implemented, it is only described in the ECMAScript specification because of legacy usage. This method should not be used since better alternatives exist.
const main = () => {
mocha.setup('bdd')
chai.should()
describe('Test Color [From Array]', function() {
let Color = new Enum('RED', 'BLUE', 'GREEN')
it('Test: Color.values()', () => {
Color.values().length.should.equal(3)
})
it('Test: Color.RED', () => {
chai.assert.isNotNull(Color.RED)
})
it('Test: Color.BLUE', () => {
chai.assert.isNotNull(Color.BLUE)
})
it('Test: Color.GREEN', () => {
chai.assert.isNotNull(Color.GREEN)
})
it('Test: Color.YELLOW', () => {
chai.assert.isUndefined(Color.YELLOW)
})
})
describe('Test Color [From Object]', function() {
let Color = new Enum({
RED: { hex: '#F00' },
BLUE: { hex: '#0F0' },
GREEN: { hex: '#00F' }
})
it('Test: Color.values()', () => {
Color.values().length.should.equal(3)
})
it('Test: Color.RED', () => {
let red = Color.RED
chai.assert.isNotNull(red)
red.getHex().should.equal('#F00')
})
it('Test: Color.BLUE', () => {
let blue = Color.BLUE
chai.assert.isNotNull(blue)
blue.getHex().should.equal('#0F0')
})
it('Test: Color.GREEN', () => {
let green = Color.GREEN
chai.assert.isNotNull(green)
green.getHex().should.equal('#00F')
})
it('Test: Color.YELLOW', () => {
let yellow = Color.YELLOW
chai.assert.isUndefined(yellow)
})
})
mocha.run()
}
class Enum {
constructor(...values) {
this.__values = []
const [first, ...rest] = values
const hasOne = rest.length === 0
const isArray = Array.isArray(first)
const args = hasOne ? (isArray ? first : Object.keys(first)) : values
args.forEach((name, index) => {
this.__createValue({
name,
index,
props: hasOne && !isArray ? first[name] : null
})
})
Object.freeze(this)
}
/* @public */
values() {
return this.__values
}
/* @private */
__createValue({ name, index, props }) {
const value = {}
Object.defineProperties(value, Enum.__defineReservedProps({
name,
index
}))
if (props) {
Object.defineProperties(value, Enum.__defineAccessors(props))
}
Object.defineProperty(this, name, {
value: Object.freeze(value),
writable: false
})
this.__values.push(this[name])
}
}
/* @private */
Enum.__defineReservedProps = ({ name, index }) => ({
name: {
value: Symbol(name),
writable: false
},
ordinal: {
value: index,
writable: false
}
})
/* @private */
Enum.__defineAccessors = (props) =>
Object.entries(props).reduce((acc, [prop, val]) => ({
...acc,
[prop]: {
value: val,
writable: false
},
[`get${Enum.__capitalize(prop)}`]: {
get: () => function() {
return this[prop]
}
}
}), {})
/* @private */
Enum.__capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1)
main()
_x000D_
.as-console-wrapper { top: 0; max-height: 100% !important; }
_x000D_
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.2.0/chai.js"></script>
<!--
public enum Color {
RED("#F00"),
BLUE("#0F0"),
GREEN("#00F");
private String hex;
public String getHex() { return this.hex; }
private Color(String hex) {
this.hex = hex;
}
}
-->
<div id="mocha"></div>
_x000D_