SELF-Treffen in Mannheim 2025

SELFHTML wird 30 Jahre alt! → Veranstaltungs-Ankündigung.

JavaScript/Datentyp

Aus SELFHTML-Wiki
< JavaScript(Weitergeleitet von Template-literal)
Wechseln zu: Navigation, Suche

Ein JavaScript-Programm hantiert mit Daten unterschiedlichen Art. Jeder Wert in JavaScript hat einen gewissen Typ. Alle Werte eines Typs ähneln sich. Sie haben gewisse Eigenschaften und Fähigkeiten.

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 man mit JavaScript verarbeiten kann, und mathematischen Operationen wie Addition oder Multiplikation.

Ein weiterer Datentyp wären die Zeichenketten, zum Beispiel "Hallo" und "Welt", mit der Operation Verkettung: "Hallo" + "Welt" ergibt "HalloWelt".[1]

Bei Zahlen und Zeichenketten handelt es sich um „einfache“ Datentypen. „Einfach“ ist hier so zu verstehen, dass ein Wert dieser Typen sich nicht weiter auspacken und zerlegen lässt. 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 sieben Typen von einfachen - oder primitiven - Datentypen:

  1. Undefined
  2. Null
  3. Boolean, Wahrheitswert, kann wahr (true) oder falsch (false) sein
  4. Number, eine Zahl, mit oder ohne Nachkommastellen.
  5. String, eine Zeichenkette, zum Beispiel "Selfhtml".
  6. Symbol, ein spezieller Typ zum Erzeugen eindeutiger Zugriffsschlüssel
  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. Einige Objekttypen bringt JavaScript bereits mit, viele weitere Objekttypen gehören zum Umfeld des Browsers und darüber hinaus kann man auch selbst Objekte und Prototypen erzeugen. Der Artikel Objekte vertieft dieses Thema weiter.

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 man zum Beispiel eine Variable deklariert, ohne ihr einen Wert zuzuweisen, so hat die Variable dennoch einen Wert – nämlich undefined. Wenn du auf eine Eigenschaft eines Objekts zugreifst, die nicht existiert, so bekommst du 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“.

Beachte: 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.

Boolean

Der Typ Boolean drückt einen Wahrheitswert aus. Der Name geht auf den englischen Mathematiker George Boole zurück, der zur Logik forschte.[2]

Es gibt genau zwei Boolean-Werte:

  • true: wahr, trifft zu
  • false: falsch, trifft nicht zu
Abfrage, ob Element mit hidden versteckt ist
    if (demoElement.hidden === false) {
      demoElement.hidden = true;
      toggleBtn.textContent = 'Zeigen';
    } else {
      demoElement.hidden = false;
      toggleBtn.textContent = 'Ausblenden';
    }

Bei einem Klick wird überprüft, ob das Element sichtbar ist. Je nach Ergebnis der booleschen Abfrage wird der Text des toggle-Buttons geändert.

Boolean-Werte werden überall dort benutzt, wo es um Ja/Nein-Entscheidungen geht: Ist ein Element sichtbar? Enthält eine Liste einen gesuchten Wert? Ist die Eingabe in ein Formularfeld gültig? Ist der Benutzer eingeloggt?

Boolean-Werte sind auch das Ergebnis von Vergleichsoperatoren:

alter >= 18

Ist das Alter größer oder gleich 18?


userName === ''

Ist der Nutzername leer?

Number

Der Typ Number umfasst in JavaScript sowohl Ganzzahlen (integer) als auch Dezimalzahlen (float) bis zu einer Größe von 21023 × (2 - 2-52) (Für größere Zahlen gibt es seit ES2020 den BigInt-Datentyp.)

Es wird ein System verwendet, das als „64-Bit-Format mit doppelter Genauigkeit“ bezeichnet wird.[3]

Man kann Zahlen ganz normal notieren. Beachte dabei nur, dass bei Kommazahlen anstelle eines Kommas ein Punkt verwendet werden muss. So wird die Zahl Pi beispielsweise als 3.1415 notiert. Für sehr hohe und sehr niedrige Zahlen und für komplexe Dezimalzahlen gibt es daneben aber noch andere Notationsmöglichkeiten.

Beispiel
    var a = 1E1;
    var b = 1.2345E4;
    var c = 2e-3;

Mit e oder E bestimmt man die Zehnerpotenz bzw. die Anzahl Nullen, die hinter der Zahl vor dem e bzw. E stehen.

Die erste Zahl im Beispiel, 1E1, ist eine 1 mit einer 0 dahinter, also 10.

Die zweite Zahl im Beispiel, 1.2345E4, ist eine andere Schreibweise für 12345.
Der Dezimalpunkt wird also einfach um so viele Stellen nach rechts verschoben, wie hinter dem E-Zeichen angegeben.

Die dritte Zahl im Beispiel, 2e-3, ist eine andere Schreibweise für 0.002.
Der Dezimalpunkt wird also einfach um so viele Stellen nach links verschoben, wie hinter dem E-Zeichen angegeben.

Diese umgekehrte Richtung wird durch das Minuszeichen bewirkt, das hinter dem e folgt.

String

Der Typ String (englisch für Faden, Schnur) erlaubt das Arbeiten mit Zeichenketten. Darin kann man einzelne Zeichen bis hin zu ganzen Texten speichern. Es sind alle Zeichen möglich, die im globalen Unicode-Standard registriert sind. Das sind die Buchstaben, Zeichen und Symbole aller großen und kleinen Schriften und Sprachen.

Strings können mithilfe des String-Literals erzeugt werden. Er beginnt und endet mit einfachen oder doppelten Anführungszeichen. Dazwischen werden die gewünschten Zeichen notiert.

let vorname = 'Alice';
let nachname = "Lidell";

Ob du als Begrenzer zwei einfache Anführungszeichen '…' oder zwei doppelte Anführungszeichen "…" benutzt, ist dir überlassen. Beide Schreibweisen sind gleichwertig. Allerdings ergeben sich Probleme, wenn der String selbst diese Zeichen enthält. Innerhalb des Strings kann man die jeweiligen Begrenzer nicht verwenden:

var text = ""Nein, gewiß nicht!" sagte Alice"; // Fehler!

Eine Lösungsmöglichkeit ist, die jeweils anderen Anführungszeichen zu verwenden, die nicht im String verwendet werden:

let text = '"Nein, gewiß nicht!" sagte Alice';
let text = "'Nein, gewiß nicht!' sagte Alice";

Oder man macht die Begrenzer innerhalb des Strings mit einem Schrägstrich \ davor unschädlich. Aus " wird \" und aus ' wird \':

let text = "\"Nein, gewiß nicht!\" sagte Alice";
let text = '\'Nein, gewiß nicht!\' sagte Alice';

JavaScript-Programme arbeiten häufig mit Strings. Die meisten Nutzereingaben und Dokumentinhalte sind einzelne Zeichen oder längere Texte, die in JavaScript als Strings vorliegen.

Zeichenkettenverknüpfung

Mit einem einfachen Pluszeichen + kann man eine Zeichenkette an eine andere anhängen.


Zeichenkettenverknüpfung
    let vorname = 'Stefan',
        zuname  = 'Muenz';
    let name    = vorname + ' ' + zuname + ', der Autor dieses Dokuments';

Zwischen beiden Variablen findet sich eine Teilzeichenkette mit einem Leerzeichen zur Trennung; alle Teilzeichenketten werden mit + aneinandergefügt.

Bei umfangreichen Zeichenketten wird die Kombination von Zeichenketten in Anführungszeichen und dem Operator + immer komplexer, deshalb verwendet man heute dafür …

Template-Literale

Template-Literale sind eine besondere Form von Zeichenketten, die mit ECMAScript 6 in den Sprachstandandard aufgenommen wurden. Sie entsprechen semantisch in etwa den aus PHP bekannten heredoc-Strings.[4][5][6]

Ein Template-Literal unterscheidet sich syntaktisch von einem String dadurch, dass es `Backticks` (rückwärts geneigte Hochkommas) als Begrenzerzeichen verwendet, statt der bekannten ' oder " Zeichen. Darüber hinaus kann ein Template-Literal auch über mehrere Zeilen hinweg gehen, die Zeilenumbrüche werden in ein Linefeed-Zeichen (\n) umgewandelt.

Innerhalb eines Template-Literals können, begrenzt durch ${ und }, beliebige Javascript-Ausdrücke eingesetzt werden. Das ermöglicht das kompakte Zusammensetzen längerer Zeichenketten aus vielen festen und variablen Teilen.

Beispiel
auto = { marke: "Acme",
         modell: "08/15",
         treibstoff: "Kerosin",
         verbrauch: "17 gal" };
  
info = `Ein ${auto.marke} ${auto.modell} verbraucht ${auto.verbrauch} ${auto.treibstoff} auf 100 km.`;

Ergibt: "Ein Acme 08/15 verbraucht 17 gal Kerosin auf 100 km.";

Beispiel
formFeld = { label: "Name", formVar: "name", wert: 4711 };

html = `<div>
  <label for='${formFeld.formVar}'>${formFeld.label}:
    <input type='text' name='${formFeld.formVar}' value='${formFeld.wert}'>
  </label>
</div>`;
Ergibt:
<div>
  <label for='name'>Name:
    <input type='text' name='name' value='4711'>
  </label>
</div>

Soll innerhalb eines Template-Literals ein Backtick oder die Zeichenfolge ${ als Text verwendet werden, so ist ein Backslash als Escape-Zeichen voranzustellen:

Beispiel
var a = 1,
    b = 2, 
    c = 3;
var muster = `Das Template \`\${a} + \${b} = \${c}\` wird für a=${a}, b=${b} und c=${c} zu "${a} + ${b} = ${c}"`

Ergibt: Das Template `${a} + ${b} = ${c}` wird für a=1, b=2 und c=3 zu "1 + 2 = 3"

Tagged Template Literal

Als Tagged Template Literal bezeichnet man eine spezielle Verknüpfung einer Funktion mit einem Templateliteral. Die Funktion wird in diesem Zusammenhang als das Tag bezeichnet. JavaScript verwendet hierfür eine spezielle Syntax, bei der der Funktionsname direkt vor das Templateliteral geschrieben wird

Mittels eines Tagged Templateliterals kann man das Parsen eines Templateliterals und das Einsetzen der Werte in das Resultat voneinander trennen. Das Parsen übernimmt weiterhin Javascript, die weitere Verarbeitung das angegebene Tag. Das Ergebnis des Parsers besteht aus den Abschnitten, die als Klartext im Templateliteral standen, und den Werten für die verwendeten Platzhalter. Die Textabschnitte werden der Tag-Funktion im ersten Parameter bereitgestellt, die ermittelten Werte für die Platzhalter als weitere Parameter.

Der erste Parameter mit den Textabschnitten ist einem Array ähnlich. Er enthält wie ein Array die gefundenen Textabschnitte an den Indexpositionen ab 0, und es gibt auch eine length-Eigenschaft. Zusätzlich gibt es aber noch die Eigenschaft raw, die wiederum ein Array darstellt und die Textabschnitte in ihrer Sourcecode-Form enthält, d.h. Escape-Sequenzen sind darin nicht in ihre Unicode-Entsprechung übersetzt worden. Das raw-Array ist nützlich, wenn man Templates hat, deren Inhalt nicht den Escaping-Regeln von JavaScript folgt, wie beispielsweise LaTeX.

Beispiel
const sh = "SelfHTML";
alert(quote`Hallo ${sh}!`;     // Zeigt Hallo "SelfHTML"!

function quote(parts, value) {
   return parts[0] + '"' + value + '"' + parts[1];
}

Die Tag-Funktion quote erwartet ein Template aus zwei Textabschnitten und einem Platzhalterwert. Sie ergänzt den Platzhalterwert um Anführungszeichen, setzt ihn mit den beiden Textabschnitten zusammen und gibt die entstandene Zeichenkette zurück.

Ein Templateliteral mit einem Platzhalter am Anfang oder Ende erfährt eine Sonderbehandlung, die dir die Verarbeitung erleichtert. In einem Templateliteral wie `Hallo ${var}` könnte man naiv sagen, dass es einen Textabschnitt und einen Platzhalterwert gibt und der Tag-Funktion das Array [ "Hallo " ] als erstes Argument übergeben. Eine Tag-Funktion wüsste dann aber nicht, ob dieser Abschnitt vor oder hinter den Platzhalterwert gehört. Deshalb fügt JavaScript noch einen Leerstring ein und übergibt dir [ "Hallo ", "" ]. Das entsprechende geschieht, wenn ein Platzhalter am Anfang des Templateliterals steht, so dass du immer genau einen Textabschnitt mehr hast als Platzhalterwerte.

Das folgende Beispiel zeigt die Verwendung von raw in einer Tag-Funktion, die Templates mit LaTeX-Befehlen ermöglicht. Normalerweise muss man für einen Latex-Befehl jeden Backslash verdoppeln; um \frac{1}{2} zu erzeugen, müsste man `\\frac{${zähler}}{${nenner}}` schreiben. Denn in `\frac...` würde JavaScript eine gültige Escapesequenz \f erkennen und das ASCII-Steuerzeichen U+000C (Seitenvorschub) erzeugen. Mit Hilfe einer Tagfunktion und den raw-Abschnitten kann man das verhindern:

Beispiel
const zähler=3, nenner=5;
console.log(`\frac{${zähler}}{${nenner}}`);   // gibt einen FormFeed und rac{3}{5} aus!
console.log(latex`\frac{${zähler}}{${nenner}}`);

function latex(parts, ...values) {
   let result = parts.raw[0];
   for (let i=0; i<values.length; i++) {
      result += values[i] + parts.raw[i+1];
   }
   return result;
}

Die Tag-Funktion latex setzt die raw-Werte der Textabschnitte und die Platzhalterwerte abwechselnd zusammen.

Beachte: Die Funktion latex musst du nicht selbst programmieren, sie ist unter anderem Namen bereits vorhanden: String.raw.

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. Du kannst 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 du unbedingt einem String oder einer Zahl eine weitere Eigenschaft hinzufügen möchtest, musst du 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.


Anhang: Steuerzeichen bei Zeichenketten

Bei Zeichenkettenvariablen gibt es die Möglichkeit, Steuerzeichen in den Variablenwert einzufügen.

Beispiel
    var Variable1 = "Hier erfolgt ein\"Anführungszeichen";
    var Variable2 = "Hier erfolgt ein\\Backslash";
    var Variable3 = "Hier erfolgt ein\nZeilenvorschub (Linefeed, LF)";
    var Variable4 = "Hier erfolgt ein\rWagenrücklauf (Carriage Return, CR)";
    var Variable5 = "Hier erfolgt ein\tTabulator";
    var Variable6 = "Hier erfolgt ein\bBackspace";
    var Variable7 = "Hier erfolgt ein\fSeitenvorschub (Formfeed, FF)";


Steuerzeichen dieser Art werden durch das Zeichen \ eingeleitet. Dahinter folgt ein Buchstabe, der das Steuerzeichen markiert.

Steuerzeichen Beschreibung Anwendung
\' einfaches Anführungszeichen innerhalb einer Zeichenkette Ein Anführungszeichen würde das Ende der Zeichenkette bedeuten. So ist es Teil der Zeichenkette.
\" normales Anführungszeichen innerhalb einer Zeichenkette
\\ Rückwärtsschrägstrich (Backslash)
\n Zeilenumbruch (New Line) in alert-Meldungen sinnvoll, um innerhalb des auszugebenden Textes einen Zeilenumbruch einzufügen.
\r neue Zeile (Carriage Return) ist in Kombination mit \n als Zeilenvorschub in DOS-Systemen vorgesehen. Ihre Verwendung in JavaScript ist auch unter Windows im Allgemeinen nicht notwendig.
\t Tabulatorzeichen sinnvoll, um etwa innerhalb einer alert(...)-Meldung tabellarische Information auszugeben.
\b Backspace entspricht der Backspace-Taste der Tastatur und löscht das vorhergehende Zeichen in der Ausgabe.
\f Seitenvorschub (Formfeed) dient bei Druckern dazu, die aktuell bedruckte Seite auszuwerfen und auf einer frischen Seite weiterzudrucken. Sie dürfte in der Praxis keinerlei Relevanz für JavaScriptanwendungen haben.
\uXXXX Unicode-Escapesequenz zur Notation von (Unicode-) Zeichen außerhalb der gewählten Zeichencodierung

Weblinks

  1. Data structures (developer.mozilla.org)
  2. George Boole (de.wikipedia.org)
  3. Double-precision floating-point format (en.wikipedia.org)
  4. ES6 In Depth: Template strings Jason Orendorff (hacks.mozilla.org)
  5. Jack Hsus Blogbeitrag mit der Idee zu dem Formatierer: I18N with ES2015 Template Literals
  6. Mozilla Developer Network: Template literals
  7. Mathias Schäfer: Organisation von JavaScripten: Datentypen und Kernobjekte