Alle Programmiersprachen besitzen eingebaute Datenstrukturen. Diese unterschieden sich aber je nach Programmiersprache. Dieser Artikel versucht, die in JavaScript verfügbaren Datenstrukturen und ihre Eigenschaften zu erläutern. Auf Basis dieser können wiederum neue Datenstrukturen erstellt werden. Außerdem werden an passenden Stellen Vergleiche zu anderen Programmiersprachen gezogen.
Dynamische Typisierung
JavaScript ist eine schwach typisierte oder dynamische Programmiersprache. Das bedeutet, dass der Datentyp einer Variable nicht explizit deklariert werden muss. Er wird automatisch bestimmt, während das Programm ausgeführt wird. Somit kann dieselbe Variable verschiedene Datentypen haben:
var foo = 42; // foo is a Number now var foo = "bar"; // foo is a String now var foo = true; // foo is a Boolean now
Datentypen
Der aktuelle ECMAScript Standard definiert sieben Datentypen:
- Sechs Datentypen sind primitives:
- und Object
Primitive Werte
Alle Datentypen bis auf Object definieren unveränderbare Werte (Werte, die nicht verändert werden können). Zum Beispiel im Gegensatz zu C sind Strings unveränderbar. Die Werte dieser Datentypen werden als "primitive values" bezeichnet.
Boolean Datentyp
Boolean repräsentiert eine logische Einheit und kann zwei Werte annehmen: true
und false
.
Null Datentyp
Der Null Typ hat genau einen Wert: null
. Siehe null
und Null für mehr Details.
Undefined Datentyp
Eine Variable, der noch kein Wert zugeweisen wurde, hat den Wert undefined
. Siehe undefined
und Undefined für mehr Details.
Number Datentyp
Laut dem ECMAScript Standard gibt es nur einen Datentyp für Zahlen: double-precision 64-bit binary format IEEE 754 value (Zahlen zwischen -(253 -1) und 253 -1). Es gibt keinen spezifischen Datentyp für Ganzzahlen. Neben Gleitkommazahlen kann der Datentyp für Zahlen auch drei symbolische Werte annehmen: +Infinity
, -Infinity
und NaN
(not-a-number = keine Zahl).
Um auf größere oder kleinere Werte als +/-Infinity
zu prüfen, können die Konstanten Number.MAX_VALUE
oder Number.MIN_VALUE
verwendet werden. Ab ECMAScript 6 kann auch geprüft werden, ob sich eine Zahl innerhalb des Bereichs der Gleitkommazahlen mit doppelter Präzision befindet. Die ist mit Number.isSafeInteger()
als auch Number.MAX_SAFE_INTEGER
und Number.MIN_SAFE_INTEGER
möglich. Zahlen außerhalb diesen Bereichs sind in JavaScript nicht mehr sicher.
Der Datentyp für Zahlen hat eine Ganzzahl mit zwei Repräsentationen: 0 kann als -0 und +0 repräsentiert werden. ("0" ist ein Alias für +0). In der Praxis hat dies fast keinen Einfluss. +0 === -0
ist zum Beispiel true
. Eine Division ergibt aber zwei unterschiedliche Werte:
> 42 / +0 Infinity > 42 / -0 -Infinity
Obwohl eine Zahl oft ihren Wert repräsentiert, bietet JavaScript eingie binäre Operatoren an. Mit ihnen können zum Beispiel mehrere Boolean Werte innerhalb eine einzigen Zahl mittels Bitmaskierung repräsentiert werden. Dies gilt generell als Bad Practice, doch JavaScript bietet keinen anderen Weg an, um eine Menge von Booleans zu repräsentierten (wie zum Beispiel ein Array von Booleans oder ein Objekt mit Boolean Werten als benannte Eigenschaften). Bitmaskierung neigt dazu, das Code schwerer zu lesen, verstehenh und warten ist. In sehr speziellen Anwendungsgebiete kann Bitmaskierung notwendig sein. Zum Beispiel wenn nur geringe Speichermengen verfügbar sind oder in extremen Fällen, wenn jedes übertragene Bit im Netzwerk zählt. Diese Technik soll aber als letzter Ausweg gesehen werden, um die Größe zu optimieren.
String Datentyp
Der Datentyp String wird in JavaScript für die Repräsentation von textuellen Daten verwendet. Er ist eine Menge von "Elementen" aus 16-Bit vorzeichenlosen Ganzzahlenwerten. Jedes Element im String nimmt eine Position im String ein. Das erste Element befindet sich an der Position mit dem Index 0, das nächste beim Index 1 und so weiter. Die Länge eines String ist die Anzahl der sich darinbefindenden Elemente.
In Gegensatz zu anderen Programmiersprachen wie C kann ein String in JavaScript nicht verändert werden. Das bedeutet, dass ein String nicht mehr verändet werden kann, nachdem er erstellt wurde. Es ist aber möglich einen anderen String mit der Hilfe von Operationen aus dem ursprünglichen String zu erstellen:
- Eine Teilzeichenfolge vom ursprünglichen String durch das Auswählen von bestimmten Zeichen oder mit der Methode
String.substr()
. - Eine Verkettung von zwei Strings mit dem Operator (
+
) oderString.concat()
.
Vermeiden Sie "stringly-typing" in Ihrem Code!
Es kann verlockend sein mit String komplexe Daten zu repräsentieren. Es bringt kurzfristige Vorteile mit sich:
- Komplexe Strings können einfach durch Verkettung erstellt werden.
- Strings sind einfacher im Debug (die Ausgabe entspricht dem Inhalt vom String).
- Strings sind bei vielen APIs gebräuchlich (Eingabefeldern, Local Storage Werte,
XMLHttpRequest
Antworten im der EigenschaftresponseText
, etc.). Dadurch kann es verlockend sein nur mit Strings zu arbeiten.
Ohne Konventionen kann jede Datenstruktur als String repräsentiert werden. Dies ist aber keine gute Idee. Es könnte zum Beispiel eine Liste emuliert werden indem die Listenelemente im String durch einen Separator getrennt werden. In diesem Fall ist ein JavaScript Array aber geeigneter, denn die Liste kann zerstört werden sobald ein Listenelement den Separator enthält. Ein Escape-Zeichen oder Ähnliches müsste verwendet werden. Dafür sind aber zusätzliche Konventionen nötig und der Wartung des Codes nimmt an Komplexität zu.
Strings sollten nur für textuelle Daten verwendet werden. Wenn komplexte Daten repräsentiert werden sollen, parsen Sie den String und verwenden Sie eine geeignete Abstraktion.
Symbol Datentyp
Symbole in JavaScript sind mit der ECMAScript Edition 6 eingeführt worden. Ein Symbol ist ein eindeutiger und unveränderbarer primitiver Wert. Es kann als Key einer Eigenschaft eines Objekts (siehe unten) verwendet werden. In manchen Programmiersprachen werden Symbols auch Atoms genannt. Sie können auch mit benannten Aufzählungen (enum) in C verglichen werden. Details dazu sind unter Symbol und dem Symbol
Object Wrapper in JavaScript zu finden.
Objekte
Objekte in der Informatik sind Werte im Speicher, die möglicherweise über einen identifier referenziert werden.
Properties (Eigenschaften)
In JavaScript können Objekte als eine Sammlung von Properties angesehen werden. Mit der Object Literal Syntax werden die nötigsten Properties initialisiert. Danach können Properties hinzugefügt oder wieder entfernt werden. Der Wert eines Property kann von jedem Datentyp sein. Darunter können sich auch andere Objekte befinden. Dadurch können komplexe Datenstrukturen realisiert werden. Properties werden mit einem Key identifiziert. Ein Key ist entweder ein String oder ein Symbol.
Es gibt zwei Arten von Properties, welche bestimmte Attribute haben: Das Data Property und das Accessor Property.
Data Property
Assoziiert einen Key mit einem Wert und besitzt die folgenden Attribute:
Attribut | Datentyp | Beschreibung | Standardwert |
---|---|---|---|
[[Value]] | beliebiger JavaScript Datentyp | der Wert, der bei einem Get-Zugriff auf das Property zurückgegeben wird | undefined |
[[Writable]] | Boolean | false , wenn [[Value]] des Property nicht verändert werden kann |
false |
[[Enumerable]] | Boolean | true , wenn das Property in for...in Schleifen aufgelistet wird |
false |
[[Configurable]] | Boolean | false , wenn das Property nicht gelöscht und andere Attribute als [[Value]] und [[Writable]] nicht verändert werden können. |
false |
Accessor Property
Assoziiert einen Key mit einer oder zwei Accessor-Funktionen (get und set), um einen Wert zu erhalten oder zu speichern. Es besitzt die folgenden Attribute:
Attribut | Datentyp | Beschreibung | Standardwert |
---|---|---|---|
[[Get]] | Funktionsobjekt oder undefined | Die Funktion wird ohne ein Argument aufgerufen und gibt den Wert des Property zurück, sobald ein Get-Zugriff auf den Wert ausgeführt wird. Siehe auch get . |
undefined |
[[Set]] | Funktionsobjekt oder undefined | Die Funktion wird mit einem Argument aufgerufen, das den Wert für die Zuweisung enthält. Sie wird immer aufgerufen, sobald ein bestimmtes Property verändert werden soll. Siehe auch set . |
undefined |
[[Enumerable]] | Boolean | true , wenn das Property in for...in Schleifen aufgelistet wird |
false |
[[Configurable]] | Boolean | false , wenn das Property nicht gelöscht und nicht zu einer Dateneigenschaft verändert werden kann |
false |
"Normale" Objekte und Funktionen
Ein Objekt in JavaScript ist ein Mapping zwischen Keys und Werten. Keys sind Strings oder Symbole und Werte können von jedem Datentyp sein. Dadurch sind Objekte eine Art Hashmap.
Funktionen sind reguläre Objekte mit der Fähigkeit direkt aufgerufen werden zu können.
Datum
Mit der in JavaScript eingebauten Date
Utility kann ein Datum repräsentiert werden.
Indizierte Collections: Arrays und typisierte Arrays
Arrays sind reguläre Objekte bei denen eine Beziehung zwischen Eigenschaften, die über Ganzzahlen indizeirt werden, und der 'length' Eigenschaft besteht. Zusätzlich erben Arrays von Array.prototype
, welcher Helfermethoden zur Manipulation von Arrays anbietet, wie zum Beispiel indexOf
(zur Suche eines Werts im Array) oder push
(Elemente zu einem Array hinzufügen). Dadruch können Listen und Mengen über ein Array repräsentiert werden.
Typisierte Arrays sind in JavaScript mit ECMAScript Edition 6 eingeführt worden. Sie bieten eine array-ähnliche Sicht auf einen darunterliegenden binären Datenpuffer an. Die folgende Tabelle stellt äquivalente C Datentypen dar:
TypedArray objects
Type | Size | Description | Web IDL type | Equivalent C type |
Int8Array |
1 | 8-bit twos complement signed integer | byte |
int8_t |
Uint8Array |
1 | 8-bit unsigned integer | octet |
uint8_t |
Uint8ClampedArray |
1 | 8-bit unsigned integer (clamped) | octet |
uint8_t |
Int16Array |
2 | 16-bit twos complement signed integer | short |
int16_t |
Uint16Array |
2 | 16-bit unsigned integer | unsigned short |
uint16_t |
Int32Array |
4 | 32-bit twos complement signed integer | long |
int32_t |
Uint32Array |
4 | 32-bit unsigned integer | unsigned long |
uint32_t |
Float32Array |
4 | 32-bit IEEE floating point number | unrestricted float |
float |
Float64Array |
8 | 64-bit IEEE floating point number | unrestricted double |
double |
Keyed Collections: Maps, Sets, WeakMaps, WeakSets
Diese Datenstrukturen verwenden Objektreferenzen als Keys. Sie wurden mit ECMAScript Edition 6 eingeführt. Set
und WeakSet
repräsentieren eine Menge von Objekten, während Map
und WeakMap
einen Wert mit einem Objekt assoziieren. Der Unterschied zwischen Maps und WeakMaps ist, dass bei Maps die über Objekt-Keys iteriert werden kann. Das erlaubt eine spätere Optimierung der Garbage Collection.
Maps und Sets könnten in reinem ECMAScript 5 implementiert werden. Da Objekte aber nicht verglichen werden können (im Sinne von zum Beispiel "kleiner gleich"), wäre die Performance für einen Look-Up linear. Native Implementierungen (inklusive WeakMaps) können eine ungefähr logarithmische Look-Up Performance haben.
Um Daten an einen DOM-Knoten zu binden, werden normalerweise die Properties direkt auf dem Objekt gesetzt oder die data-*
Attribute verwendet. Das hat aber den Nachteil, dass die Daten für jedes Skript in demselben Kontext verfügbar sind. Mit Maps und WeakMaps können Daten einfach privat an ein Objekt gebunden werden.
Strukturierte Daten: JSON
JSON (JavaScript Object Notation) ist ein leichtgewichtges Format zum Datenaustausch, welches von JavaScript abgeleitet aber auch von vielen anderen Programmiersprachen verwendet wird. JSON können universelle Datenstrukturen aufgebaut werden. Siehe JSON und JSON
für mehr Details.
Mehr Objekte in der Standardbibliothek
JavaScript hat eine Standardbibliothek mit zahlreichen eingebauten Objekten. Details darüber sind unter Referenz zu finden.
Datentypen mit dem typeof
Operator bestimmen
Der typeof
Operator kann den Datentyp einer Variablen herausfinden. Unter der Referenzseite sind mehr Details und Grenzfälle zu finden.
Spezifikationen
Spezifikation | Status | Kommentar |
---|---|---|
ECMAScript 1st Edition. | Standard | initiale Definition |
ECMAScript 5.1 (ECMA-262) Die Definition von 'Types' in dieser Spezifikation. |
Standard | |
ECMAScript 6 (ECMA-262) Die Definition von 'ECMAScript Data Types and Values' in dieser Spezifikation. |
Anwärter Empfehlung |