JavaScript/Datentyp

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

In JavaScript gibt es sieben verschiedene Datentypen. Ein Datentyp bezeichnet eine bestimmte Menge gleichartiger Werte und legt fest, welche Operationen man mit ihnen ausführen kann. Ein Beispiel dafür ist die Menge aller Zahlen, die Sie mit JavaScript verarbeiten können, und mathematischen Operationen wie Addition oder Multiplikation. Ein weiterer Typ wären die Zeichenketten, zum Beispiel "Hallo" und "Welt", mit der Operation Verkettung: "Hallo" + "Welt" ergibt "HalloWelt".

Bei Zahlen und Zeichenketten handelt es sich um einfache Datentypen. „Einfach“ ist hier so zu verstehen, dass ein Wert dieser Typen nicht aus mehreren Teil-Werten zusammengesetzt ist. Bei Zeichenketten könnte man argumentieren, dass eine Zeichenkette aus Zeichen zusammengesetzt sei. Diese Aussage ist nicht grundsätzlich falsch, aber für das Programmiermodell von JavaScript trifft sie nicht zu. Hier wird eine Zeichenkette als einfacher Wert aufgefasst.

Insgesamt verfügt JavaScript über sechs Typen von einfachen - oder primitiven - Datentypen:

  1. Undefined
  2. Null
  3. Boolean, Wahrheitswert, kann wahr (true) oder falsch (false) sein
  4. String, eine Zeichenkette, zum Beispiel "Selfhtml".
  5. Symbol, ein spezieller Typ zum Erzeugen eindeutiger Zugriffsschlüssel
  6. Number, eine Zahl, mit oder ohne Nachkommastellen.
  7. BigInt, ein ganzzahliger Wert beliebiger Größe

Im Gegensatz dazu stehen die Objekte. Sie unterscheiden sich von primitiven Typen dadurch, dass sie nicht nur einen Wert darstellen, sondern eine Sammlung von beliebigen Werten und Funktionen bilden. Objekte können frei zusammengesetzt sein, sie können aber auch einer bestimmten Vorlage entsprechen, was man oft als Klasse bezeichnet. Das Modell von JavaScript ist etwas anders, es verwendet statt Klassen so genannte Prototypen. Einige Objekttypen bringt JavaScript bereits mit, viele weitere Objekttypen gehören zum Umfeld des Browsers und darüber hinaus können Sie auch selbst Objekte und Prototypen erzeugen. Der Artikel Objekte vertieft dieses Thema weiter.

An dieser Stelle soll noch ein Überblick über die primitiven Typen folgen.

undefined

Der Typ Undefined hat nur einen möglichen Wert, nämlich undefined. Das klingt erst einmal verwirrend. Manche Werte sind aber so einzigartig, dass sie ihren eigenen Typ haben.

Der Wert undefined steht für „leer, noch kein Wert zugewiesen“. Verschiedene JavaScript-interne Operationen können undefined zurückgeben.

Wenn Sie zum Beispiel eine Variable deklarieren, ohne ihr einen Wert zuzuweisen, so hat die Variable dennoch einen Wert – nämlich undefined. Wenn Sie auf eine Eigenschaft eines Objekts zugreifen, die nicht existiert, so bekommen Sie den Wert undefined zurück.

undefined wird also intern in JavaScript an verschiedenen Stellen genutzt, um „kein Wert vorhanden“ darzustellen.

null

Der Typ Null hat ebenfalls nur einen möglichen Wert, nämlich null.

Der Wert null steht für „absichtlich kein Wert“. Er steht auch für „absichtlich kein Objekt“ dort, wo ein Objekt sein könnte.

Es gibt in JavaScript beispielsweise Funktionen, die üblicherweise Objekte zurückgeben. Wenn sie kein Objekt zurückgeben können, etwa weil sie nichts gefunden haben, dann geben sie null zurück.

Der Unterschied zwischen undefined und null ist sehr subtil. Beide sind Platzhalter für „leer“ und „kein Wert“ mit dem feinen Unterschied „kein Wert zugewiesen“ und „absichtlich kein Objekt“.

Beachten Sie: JavaScript besitzt einen Operator namens typeof, der den Typ eines Wertes zurückgibt. typeof null liefert "object" als Ergebnis. Trotzdem wird null als eigener Typ angesehen und nicht als ein Objekt.

Weitere primitive Typen

Die Typen Boolean, String, Symbol und Number werden in eigenen Artikeln behandelt.

Spezielle Objekttypen

Es gibt einige Objekttypen, die in anderen Programmiersprachen eher primitive Typen sind, oder gar kein Datentyp. Deswegen sollen sie hier kurz vorgestellt werden.

  • Function, eine Aneinanderreihung von Anweisungen. Funktionen sind in vielen Programmiersprachen einfach Teil der Sprache und dienen der Gliederung der Programme in kleinere, wiederverwendbare Einheiten. Das ist in JavaScript auch so, aber darüber hinaus ist eine Funktion ein vollwertiges Objekt. Außer die Funktion aufzurufen, kann man einem Funktionsobjekt auch Eigenschaften zuweisen, man kann es in einer Variablen speichern oder als Parameter an andere Funktionen übergeben. Die Klammern, die in JavaScript einen Funktionsaufruf kennzeichnen, werden so zu mehr als nur einem Syntaxelement der Sprache, sie sind ein eigener Operator.
  • Array, eine Sammlung von Werten, auf die mit einem ganzzahligen Index zugegriffen werden kann. Arrays haben eine length Eigenschaft, die automatisch den Wert des höchsten genutzten Index plus eins darstellt, ansonsten verhalten sie sich wie normale Objekte.

Eine weitere spezielle Art von Objekten sind die sogenannten Wrapper für primitive Typen. Das Programmiermodell von JavaScript ist so konzipiert, dass jeder Wert wie ein Objekt verwendet werden kann. Um dieses Modell auch auf die primitiven Typen (außer undefined und null) anwenden zu können, erzeugt JavaScript in dem Moment, wo ein Wert dieses Typs wie ein Objekt verwendet wird, ein temporäres Objekt, das den primitiven Wert repräsentiert. Sie können solche Wrapper auch selbst erzeugen, dafür gibt es die Konstruktorfunktionen Boolean, String und Number. Falls JavaScript einen solchen Wrapper an einer Stelle antrifft, wo ein primitiver Wert erwartet würde, liest es zumeist den primitiven Wert aus dem Wrapper wieder aus. Die Ausnahme sind Wrapper-Objekte vom Typ Boolean, bei denen geschieht das nicht. Boolean-Wrapperobjekte werden immer wie true behandelt (was im Artikel Boolean erläutert wird).

Wrapperobjekte selbst zu erzeugen ist normalerweise nicht sinnvoll, und wie Boolean zeigt, kann es auch verwirrende Ergebnisse liefern. Es gibt jedoch Ausnahmen. In JavaScript kann man jedem Objekt jederzeit neue Eigenschaften und Methoden hinzufügen.

Hinzufügen von Eigenschaften zu Objekten
let a = { x: 3; }
a.y = 4;
console.log(a.y);   // 4

let s = "Hallo";
s.neu = "Neue Eigenschaft";
console.log(s.neu);   // undefined

Das Beispiel zeigt, dass das Hinzufügen der Eigenschaft neu zum primitiven String in s nicht funktioniert hat. Man hätte eine kräftig-rote Fehlermeldung erwarten sollen, aber die kommt nicht; JavaScript ignoriert diese Aktion einfach. Wenn Sie unbedingt einem String oder einer Zahl eine weitere Eigenschaft hinzufügen möchten, müssen Sie ein Wrapper-Objekt dafür erzeugen.

Bei den Konstruktorfunktionen für die neueren Typen Symbol und BigInt wurde die Möglichkeit, sie mit new zu verwenden, entfernt - man kann sie als Funktion aufrufen, um Werte der primitiven Typen zu erzeugen, aber man kann sie nicht als Konstruktor für Objekte benutzen.

Der primitive Wert eines Objekts

An etlichen Stellen erwartet JavaScript einen primitiven Wert und kein Objekt. Übergibt man dennoch ein Objekt, wird es in einen primitiven Wert konvertiert. Je nach Kontext bevorzugt JavaScript dabei eine Darstellung als Zeichenkette oder als Zahl, in einigen Fällen macht der Kontext auch keine Vorgabe.

Die interne JavaScript-Operation, die dafür genutzt wird, unterscheidet zwischen „exotischen“ und „gewöhnlichen“ Objekten. Dabei übernimmt ein exotisches Objekt die Konvertierung selbst, während bei einem gewöhnlichen Objekt ein Standardalgorithmus angewendet wird.

Exotisch sind zum einen Symbole, die als primitiven Wert immer nur den primitiven Symbolwert zurückliefern. Zum anderen sind es Date-Objekte, die sich bei einer fehlenden Vorgabe für die Darstellung vorzugsweise in eine Zeichenketten-Darstellung konvertieren und nur dann die Darstellung als Zahl (einen Unix-Timestamp) liefern, wenn der Kontext es ausdrücklich fordert.

Der Standardalgorithmus verwendet die Methoden valueOf und toString des zu konvertierenden Objekts, um einen primitiven Wert zu erhalten. Er beginnt dabei mit valueOf, es sei denn, der Kontext bevorzugt ausdrücklich die Darstellung als Zeichenkette.

Für jede der beiden Methoden wird geschaut, ob das Objekt sie implementiert. Wenn ja, wird sie aufgerufen. Ist das Ergebnis ein primitiver Wert, ist dies der primitive Wert des Objekts. Wenn nicht, wird die andere Methode ausprobiert. Wenn beide Methoden fehlen oder keinen primitiven Wert liefern, wirft JavaScript einen TypeError.

"Bevorzugen" einer Darstellung bedeutet nicht, dass dies Pflicht wäre. Wenn ein Objekt sich nicht als Zahl darstellen lässt, sondern nur als Zeichenkette (z. B. "[object Array]"), dann ist das so, und JavaScript muss dann das Beste daraus machen. Oder doch noch einen TypeError werfen, wenn an dieser Stelle mit einer Zeichenkette gar nichts anzufangen ist.

ToDo (weitere ToDos)

  • Datentypen muss vor Variablen gesetzt werden
  • Literale aller Art sollten hier erklärt werden - bei Arrays und Objekten nur kurz angerissen
  • Erklärungen, was Literale sind, sollten ausgedünnt werden und hierher zeigen
  • Der Redirect Literal -> template-literal sollte hierher zeigen

Quellen

  1. Mathias Schäfer: Organisation von JavaScripten: Datentypen und Kernobjekte