Ein enum für JavaScript

the next big thing  –  10 Kommentare

Im Gegensatz zu vielen anderen Programmiersprachen kennt JavaScript keinen Aufzählungsdatentyp à la enum. Doch die Szene ist erfinderisch, wenn es darum geht, JavaScript zu erweitern. Wie lässt sich in dem Fall Abhilfe schaffen?

JavaScript kennt keinen enum-Datentyp. Trotzdem gibt es diverse Situationen, in denen ein solcher Typ hilfreich wäre. Da man die Sprache nicht selbst erweitern kann, benötigt man einen alternativen Ansatz, um den Datentyp nachbilden zu können.

Am einfachsten gelingt das mithilfe eines Objekts, dessen Eigenschaften für die Werte stehen, die der Enumeration zugewiesen werden sollen:

const accessMode = {
execute: 1,
write: 2,
read: 4
};

Prinzipiell genügt das schon, da man anschließend auf die einzelnen Werte wie gewünscht zugreifen kann:

file.accessMode = accessMode.read;

Da die Werte der Eigenschaften als Zweier-Potenzen definiert wurden, lassen sich die Werte auch problemlos miteinander kombinieren:

file.accessMode = accessMode.read | accessMode.write;

Bei Bedarf kann es zusätzlich sinnvoll sein, den Wert 0 der Eigenschaft none zuzuweisen, um abbilden zu können, dass kein Wert zugewiesen wurde:

const accessMode = {
none: 0,
execute: 1,
write: 2,
read: 4
};

file.accessMode = accessMode.none;

Unpraktisch ist allerdings, dass es theoretisch möglich ist, das accessMode-Objekt im Nachhinein zu verändern. Zwar ist die Variable accessMode als konstant markiert, das bezieht sich allerdings nur auf die Referenz an sich, nicht auf die Werte des Objekts. Um das zu ändern, muss das Objekt zusätzlich mit Object.freeze behandelt werden:

const accessMode = Object.freeze({
none: 0,
execute: 1,
write: 2,
read: 4
});

Das größte Manko an dem Vorgehen ist leider, dass der Einsatz der Enumeration nicht typsicher ist. Es ist problemlos möglich, einer Variablen einen ungültigen Wert zuzuweisen. Beispielsweise hat der Wert 8 keine Bedeutung, die entsprechende Zuweisung ist aber natürlich trotzdem möglich:

file.accessMode = 8;

Das Problem könnte man dadurch in den Griff bekommen, dass man als Werte der Enumeration keine Zahlen verwendet, sondern Symbole – allerdings verliert man dann die Möglichkeit, die einzelnen Werte durch die bitweisen Operatoren zu verknüpfen. Außerdem lassen sich Symbole nicht als JSON serialisieren, weshalb der zahlenbasierte Ansatz vorzuziehen ist.

Das wirft letztlich die Frage auf, wie sinnvoll ein derart simulierter Datentyp ist, dessen primärer Sinn darin besteht, typsicher auf benannte Werte zugreifen zu können. Die Typsicherheit kann JavaScript nicht garantieren, und die Sprache schützt auch nicht vor Schreibfehlern:

file.accessMode = accessMode.writ;
// => undefined

Sobald man diese Nachteile erkennt und akzeptiert, stellt man fest, dass man ebenso gut mit Zeichenketten arbeiten kann:

file.accessMode = 'write';

Die Typsicherheit ist bei dem Ansatz zwar auch nicht gegeben, man spart sich aber die zusätzliche Definition eines dedizierten Objekts, was letztlich kaum einen Nutzen bringt. Einzig die logische Verknüpfbarkeit bleibt als Argument – und gegebenenfalls noch eine zentrale Stelle zum Nachschlagen der gültigen Werte zu haben.

Schließlich dürfte das der Grund sein, warum die meisten Module für JavaScript auf den hier vorgestellten Ansatz verzichten und mit hart codierten Zeichenketten arbeiten: Sie sind nicht perfekt, aber für nahezu alle Anwendungsfälle gut genug und ausreichend.

Selbstverständlich kann man viel Zeit und Aufwand investieren, einen Ansatz zu entwickeln, der sich an dem enum-Datentyp anderer Programmiersprachen orientiert, aber ob das dann die Lösung darstellt, sei dahingestellt. Die Community hat sich in großen Teilen für den pragmatischen Ansatz entschieden. Warum also einen anderen Weg suchen?

tl;dr: JavaScript kennt keinen enum-Datentyp. Mithilfe eines Objekts, dessen Eigenschaften numerische Werte zugewiesen werden, lässt sich leicht Abhilfe schaffen. Tatsächlich ist das allerdings kaum besser als hart verdrahtete Zeichenketten zu verwenden.