-
enum
is a new LexicalDeclaration binding form, similar tolet
orconst
. -
typeof enum
isobject
; similar to Array, it's just a special Object (more below) -
EnumDeclaration with no BindingIdentifier creates
const
bindings corresponding to each EnumEntryName:enum { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }
Is equivalent to:
const SUNDAY = 0; const MONDAY = 1; const TUESDAY = 2; const WEDNESDAY = 3; const THURSDAY = 4; const FRIDAY = 5; const SATURDAY = 6;
-
EnumDeclaration or EnumExpression with a BindingIdentifier creates:
-
A proto-less, frozen object;
-
Creates PropertyName corresponding to each EnumEntryName:
enum DaysOfWeek { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } const DaysOfWeek = enum { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };
Is approximately* equivalent to:
const DaysOfWeek = Object.freeze( Object.create(null, { [Symbol.enumSize]: { // Specification can define better semantics for deriving // and storing the size of the enum object (internal slot) value: 7 }, [Symbol.iterator]: { * value() { // Specification can define better semantics for deriving // and storing keys and values (internal slot) let keys = Object.keys(DaysOfWeek); let values = Object.values(DaysOfWeek); let index = 0; while (index < keys.length) { yield [keys[index], values[index]]; index++; } } }, SUNDAY: { value: 0, enumerable: true }, MONDAY: { value: 1, enumerable: true }, TUESDAY: { value: 2, enumerable: true }, WEDNESDAY: { value: 3, enumerable: true }, THURSDAY: { value: 4, enumerable: true }, FRIDAY: { value: 5, enumerable: true }, SATURDAY: { value: 6, enumerable: true }, }) ); for (let [day, value] of DaysOfWeek) { console.log(value, day) } /* 0 SUNDAY 1 MONDAY 2 TUESDAY 3 WEDNESDAY 4 THURSDAY 5 FRIDAY 6 SATURDAY */
-
-
EnumDeclaration or EnumExpression will set the value of each entry to an integer, starting at 0 and incrementing by 1 for each entry.
-
EnumDeclaration may have EnumEntryName inline assignment overrides. If an entry has an inline assignment, the default value is incremented as normal, but not used for that entry.
enum { FOO, BAR = _AssignmentExpression_, BAZ, }
Is equivalent to:
const FOO = 0; const BAR = _AssignmentExpression_; const BAZ = 2;
EnumDeclaration (with BindingIdentifier) or EnumExpression example:
enum Things { FOO, BAR = _AssignmentExpression_, BAZ, } const Things = enum { FOO, BAR = _AssignmentExpression_, BAZ, };
Is approximately equivalent to:
const DaysOfWeek = Object.freeze( Object.create(null, { /* Assume Symbol.enumSize and Symbol.iterator */ FOO: { value: 0, enumerable: true }, BAR: { value: _AssignmentExpression_, enumerable: true }, BAZ: { value: 2, enumerable: true }, }) );
Of course, this means that the value of an
enum
entry can be whatever you want it to be:// todo
-
EnumDeclaration may have ComputedPropertyName as EnumEntryName:
- TODO: Am I sure about this?
enum { FOO, ["BAR"], BAZ, }
Is equivalent to:
const FOO = 0; const BAR = 1; const BAZ = 2;
EnumDeclaration (with BindingIdentifier) or EnumExpression example:
enum Things { FOO, [Symbol(...)], BAZ, } const Things = enum { FOO, [Symbol(...)], BAZ, };
Is approximately equivalent to:
const DaysOfWeek = Object.freeze( Object.create(null, { /* Assume Symbol.enumSize and Symbol.iterator */ FOO: { value: 0, enumerable: true }, [Symbol(...)]: { value: 1, enumerable: true }, BAZ: { value: 2, enumerable: true }, }) );
-
EnumDeclaration may not have duplicate EnumEntryName:
-
These throw exceptions:
enum { FOO, FOO }
enum { FOO, ["BAR"], BAR, }
-
-
EnumDeclaration with an EnumValueMap to populate the values of the Enum:
function EnumValueMap(key, index) { return 1 << index; } enum via EnumValueMap { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, } // Is equivalent to: const SUNDAY = EnumValueMap(SV(SUNDAY), 0); // 0b00000001 const MONDAY = EnumValueMap(SV(MONDAY), 1); // 0b00000010 const TUESDAY = EnumValueMap(SV(TUESDAY), 2); // 0b00000100 const WEDNESDAY = EnumValueMap(SV(WEDNESDAY), 3);// 0b00001000 const THURSDAY = EnumValueMap(SV(THURSDAY), 4); // 0b00010000 const FRIDAY = EnumValueMap(SV(FRIDAY), 5); // 0b00100000 const SATURDAY = EnumValueMap(SV(SATURDAY), 6); // 0b01000000
And the BindingIdentifier example:
function EnumValueMap(key, index) { return 1 << index; } enum DaysOfWeekAsBits via EnumValueMap { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, }
Is approximately equivalent to:
const DaysOfWeekAsBits = Object.freeze( Object.create(null, { [Symbol.enumSize]: { // Specification can define better semantics for deriving // and storing the size of the enum object (internal slot) value: 7 }, [Symbol.iterator]: { * value() { // Specification can define better semantics for deriving // and storing keys and values (internal slot) let keys = Object.keys(DaysOfWeekAsBits); let values = Object.values(DaysOfWeekAsBits); let index = 0; while (index < keys.length) { yield [keys[index], values[index]]; index++; } } }, SUNDAY: { value: EnumValueMap(SV(SUNDAY), 0), enumerable: true }, MONDAY: { value: EnumValueMap(SV(MONDAY), 1), enumerable: true }, TUESDAY: { value: EnumValueMap(SV(TUESDAY), 2), enumerable: true }, WEDNESDAY: { value: EnumValueMap(SV(WEDNESDAY), 3), enumerable: true }, THURSDAY: { value: EnumValueMap(SV(THURSDAY), 4), enumerable: true }, FRIDAY: { value: EnumValueMap(SV(FRIDAY), 5), enumerable: true }, SATURDAY: { value: EnumValueMap(SV(SATURDAY), 6), enumerable: true }, }) ); for (let [day, value] of DaysOfWeekAsBits) { console.log(value, day) } /* 0b00000001 SUNDAY 0b00000010 MONDAY 0b00000100 TUESDAY 0b00001000 WEDNESDAY 0b00010000 THURSDAY 0b00100000 FRIDAY 0b01000000 SATURDAY */
WebIDL could specify its enum as using a default EnumValueMap; ie. https://heycam.github.io/webidl/#idl-enumeration might update its definition:
An enumeration is a definition (matching Enum) used to declare a type whose valid values are a set of predefined strings.
To:
An enumeration is a definition (matching Enum) used to declare a type whose valid values are a set of predefined strings.
An ECMAScript implementation of WebIDL enum would use a String EnumValueMap.
enum RTCPeerConnectionState via String { new, connecting, connected, disconnected, failed, closed, };
Is approximately equivalent to:
const RTCPeerConnectionState =Object.freeze( Object.create(null, { [Symbol.enumSize]: { // Specification can define better semantics for deriving // and storing the size of the enum object (internal slot) value: 6 }, [Symbol.iterator]: { * value() { // Specification can define better semantics for deriving // and storing keys and values (internal slot) let keys = Object.keys(RTCPeerConnectionState); let values = Object.values(RTCPeerConnectionState); let index = 0; while (index < keys.length) { yield [keys[index], values[index]]; index++; } } }, // Note that this case illustrates that it's ok for the // for the second argument to be ignored. new: { value: String(SV(new)), enumerable: true }, connecting: { value: String(SV(connecting)), enumerable: true }, connected: { value: String(SV(connected)), enumerable: true }, disconnected: { value: String(SV(disconnected)), enumerable: true }, failed: { value: String(SV(failed)), enumerable: true }, closed: { value: String(SV(closed)), enumerable: true }, }) );
* Approximately means that it doesn't fully represent all of the semantics.