JavaScript Datentypen und Datenstrukturen

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:

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 (+) oder String.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 Eigenschaft responseText, 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:

Attribute eines Data Property
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:

Attribute eines Accessor Property
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  

Siehe auch

Schlagwörter des Dokuments und Mitwirkende

 Mitwirkende an dieser Seite: fscholz, siggi-heltau, FabianBeiner, spiegelp
 Zuletzt aktualisiert von: siggi-heltau,