Typen
Primitive Typen
Es gibt in JavaScript sieben primitive Datentypen:
numberstringbooleannullundefinedbigintsymbol
Auf die beiden Typen bigint und symbol gehe ich in dieser Einführung nicht ein. Die beiden Spezialtypen null sowie undefined werden im Abschnitt Null oder Nichts behandelt.
Primitive Werte sind unveränderlich (immutable). Bei der Übergabe an eine Funktion wird eine Kopie des Wertes übergeben.
Literale
Wie erzeugt man einen Wert eines primitiven Typs? Durch ein Literal!
// Number
const answer = 42;
console.log(typeof answer);
// String
const language = 'JavaScript';
console.log(typeof language);
// Boolean
const jsIsFun = true;
console.log(typeof jsIsFun);// Number
const answer = 42;
console.log(typeof answer);
// String
const language = 'JavaScript';
console.log(typeof language);
// Boolean
const jsIsFun = true;
console.log(typeof jsIsFun);Im kurzen Code-Snippet habe ich Variablen eingeführt bzw. deklariert. Auf dies wird im Abschnitt Syntax/Variablen eingegangen. Der typeof-Operator wird eingesetzt um den jeweiligen Datentyp zu visualisieren - in der Praxis natürlich zur Typ-Überprüfung.
Number
In JavaScript gibt es beim Zahl-Typ number keine Unterscheidung zwischen Ganzzahlen und Fließkommazahlen. Eine Zahl ist eine Zahl. Etwas technischer betrachtet entspricht der Typ number dem 64-bit Format IEEE 754 in doppelter Genauigkeit (siehe hier im MDN oder in der ECMAScript Spezifikation - etwas lesbarer in der annotierten ECMAScript 5 Spezifikation).
Literale können dezimal, binär, oktal, hexadezimal und exponential dargestellt werden.
console.log(255);
console.log(0b11111111); // 0B11111111
console.log(0377); // 0o377, 0O377
console.log(0xFF); // 0xff, 0Xff, 0XFF
console.log(255e0);console.log(255);
console.log(0b11111111); // 0B11111111
console.log(0377); // 0o377, 0O377
console.log(0xFF); // 0xff, 0Xff, 0XFF
console.log(255e0);String
Einen speziellen Datentyp für ein einzelnes Zeichen gibt es in JavaScript nicht, hier ist alles eine Zeichenkette. Die Buchstaben (Unicode, UTF-16) werden im literalen Ausdruck in Quotes eingefasst.
console.log('Eine Zeichenkette');
console.log("a");
console.log(`Eine Zeile davor ist eine Zeichenkette mit einem Zeichen`);console.log('Eine Zeichenkette');
console.log("a");
console.log(`Eine Zeile davor ist eine Zeichenkette mit einem Zeichen`);Es spielt in JavaScript keine Rolle, ob einfache Hochkommatas oder Gänsefüßchen benutzt werden. Sie unterscheiden sich lediglich beim Einfügen des Begrenzers.
console.log('It\'s somewhat "crazy"!');
console.log("It's somewhat \"crazy\"!");console.log('It\'s somewhat "crazy"!');
console.log("It's somewhat \"crazy\"!");Die dritte Form mit back-tics wurde mit JavaScript 2015 eingeführt und erlaubt Mehrzeiligkeit und Interpolation von Variablen:
const answer = 42;
console.log(`
Answer to the Ultimate Question of Life,
The Universe, and Everything: ${answer}
`);const answer = 42;
console.log(`
Answer to the Ultimate Question of Life,
The Universe, and Everything: ${answer}
`);Welche Form soll nun verwendet werden? Es ist einfach nur eine Frage nach Konvention. Möglicherweise gibt es Code-Richtlinien oder persönliche Präferenzen. Siehe auch JavaScript in Plain English
Boolean
Der Werte-Bereich des booleschen Datentyps beschränkt sich auf genau zwei Literale: true und false.
const wahr = true;
console.log(typeof wahr);
console.log(typeof false);const wahr = true;
console.log(typeof wahr);
console.log(typeof false);Wrapper-Klassen
Zu diesen drei primitiven Typen existiert jeweils eine Wrapper-Klasse mit spezifischen Eigenschaften und Methoden:
NumberStringBoolean
Konstruktor
Mit Hilfe eines Konstruktor-Aufrufes können solche Wrapper-Objekte erzeugt werden:
const zahl = new Number(42);
const engine = new String('v8');
const isPrimitive = new Boolean(false);
console.log(typeof zahl); // objectconst zahl = new Number(42);
const engine = new String('v8');
const isPrimitive = new Boolean(false);
console.log(typeof zahl); // objectMethoden und Eigenschaften dieser Wrapper-Klassen sind genau das, was man zum Beispiel unter einer klassischen String-API versteht.
console.log(engine.length);
console.log(engine.toUpperCase());console.log(engine.length);
console.log(engine.toUpperCase());Auto-Boxing
Falls literale Werte bzw. Variablen primitiven Typs in einem Objekt-Kontext benutzt werden (also ein Punkt hinter dem jeweiligen Ausdruck folgt), verpackt die JavaScript Laufzeitumgebung automatisch den primitiven Wert in einem korrespondierenden Wrapper-Objekt und stellt somit die Eigenschaften und Methoden der Wrapper-Klasse auch den primitiven Ausdrücken zur Verfügung.
console.log('Eine primitive Zeichenkette'.length);
const siteGenerator = 'Docusaurus';
console.log(siteGenerator.toUpperCase());
console.log((3.2489).toPrecision(3));console.log('Eine primitive Zeichenkette'.length);
const siteGenerator = 'Docusaurus';
console.log(siteGenerator.toUpperCase());
console.log((3.2489).toPrecision(3));Objekt Typen
Alle Daten, die keine primitiven Daten sind (also keinen primitiven Typ haben), sind von einem Objekt-Typ. Objekte sind veränderlich (mutable) und werden an Funktionen mit einer Referenz (Verweis) übergeben. Die bekanntesten vordefinierten Objekt-Typen sind Date, Array und Function. Der typeof-Operator liefert aber immer object (mit Ausnahme der Funktionen: function).
Objects
Objekte in JavaScript sind assoziative Abbildungen - also Schlüssel-Wert-Zuordnungen. Der Schlüssel-Typ (Key) ist ein string, der Wert-Typ (Value) beliebig. Die Schlüssel bezeichnet man in der OOP u.a. als Eigenschaften (Property).
Mit JavaScript 2015 wurde der primitive Datentyp
symboleingeführt. Auch Symbole sind gültige Objekt-Keys.
Literale Definition
const person = {
firstname: 'Thomas',
age: 49
};
console.log(person);const person = {
firstname: 'Thomas',
age: 49
};
console.log(person);Property Zugriff
console.log(person.name);
console.log(person['name']);console.log(person.name);
console.log(person['name']);Property Zuweisung
person.firstname = 'Marius';
person.lastname = 'Meier'; // add dynamically new property
person['age'] = 51;person.firstname = 'Marius';
person.lastname = 'Meier'; // add dynamically new property
person['age'] = 51;Arrays
Arrays in JavaScript sind Objekte mit einer speziellen Behandlung für Keys die Ganzzahlen entsprechen.
Literale Defintion
const primzahlen = [2, 3, 5, 7, 11, 13, 17, 19];
console.log(primzahlen);
console.log(primzahlen.length); // Länge des Arraysconst primzahlen = [2, 3, 5, 7, 11, 13, 17, 19];
console.log(primzahlen);
console.log(primzahlen.length); // Länge des ArraysElement-Zugriff
console.log(primzahlen[0]); // erstes Array-Element
console.log(primzahlen[7]); // letztes Element im obigen Arrayconsole.log(primzahlen[0]); // erstes Array-Element
console.log(primzahlen[7]); // letztes Element im obigen ArrayStandard-API
console.log(primzahlen.slice(4));console.log(primzahlen.slice(4));Einige Methoden mehr gibt es im Abschnitt Standard API/Arrays.
Mixed Content
Es gibt übrigens keine feste Typisierung der Array-Elemente. Also ist auch folgender gemischter Inhalt möglich:
const mixedContent = [42, 'JavaScript', true, [1, 2, 3, 4]];const mixedContent = [42, 'JavaScript', true, [1, 2, 3, 4]];Funktionen
Auch Funktionen sind in JavaScript spezielle Objekte, die aufrufbar sind. Sie können ebenso wie jeder andere Wert auch an Variablen zugewiesen sowie an andere Funktionen übergeben werden. Für Funktionen in JavaScript gilt, dass sie first-class citizens sind - ein Begriff aus der funktionalen Programmierung.
Deklaration
function add(a,b) {
return a+b;
}
console.log(add(17, 4));function add(a,b) {
return a+b;
}
console.log(add(17, 4));Definition über einen Ausdruck
const sub = function (a,b) {
return a - b;
}
console.log(sub(17, 4));const sub = function (a,b) {
return a - b;
}
console.log(sub(17, 4));Definition mit der Fat-Arrow-Syntax
const doubleValue = (z) => z * 2;
console.log(doubleValue(21));
const tripleValue = z => z * 3;
const add = (a,b) => a+b;
const sayHello = () => console.log('Hello');const doubleValue = (z) => z * 2;
console.log(doubleValue(21));
const tripleValue = z => z * 3;
const add = (a,b) => a+b;
const sayHello = () => console.log('Hello');Übergabe an andere Funktion
console.log([1,2,3,4].map(doubleValue));console.log([1,2,3,4].map(doubleValue));Null oder Nichts
JavaScript kennt zwei Werte und mit diesen jeweils formal sogar zwei eigene Datentypen für den Begriff "nichts": null und undefined.
Undefined
Der Wert undefined entspricht grob dem Konzept von nicht-existent. Es gibt verschiedene Standard-Vorkommen in der JavaScript Laufzeit-Umgebung:
- Eine Variable, die nur deklariert wurde (also ohne Zuweisung eines Wertes) ist
undefined.
let ohneWert;
console.log(ohneWert);
console.log(typeof ohneWert);
console.log(typeof notDeclared); // kein Fehler!let ohneWert;
console.log(ohneWert);
console.log(typeof ohneWert);
console.log(typeof notDeclared); // kein Fehler!- Default-Rückgabe einer Funktion
function noReturnValue() {}
const returned = noReturnValue();
console.log(returned);function noReturnValue() {}
const returned = noReturnValue();
console.log(returned);- Unbekannte Eigenschaften eines Objektes
const person = { firstname: 'Thomas' };
console.log(person.lastname);const person = { firstname: 'Thomas' };
console.log(person.lastname);- Unbesetzte Array-Indizes
const values = [];
console.log(values[5]);const values = [];
console.log(values[5]);Null
Der null-Wert wird stattdessen eher benutzt, um die Nicht-Existenz eines Objektes anzuzeigen. Also in etwa das gleiche Konzept wie hinter einer leeren Zeichenkette.
const person = null;
console.log(person);
console.log(typeof person); // "object", that's a bugconst person = null;
console.log(person);
console.log(typeof person); // "object", that's a bugIn der Praxis wird diese Trennung durchaus aufgeweicht.
Typ-Umwandlung
Hier betrachte ich lediglich die relevanten Umwandlungen (casting) von Zahl-Werten in Zeichenketten und zurück.
Nach Zeichenkette
const zahl = 42;
let zahlStr = zahl.toString();
console.log(zahlStr, typeof zahlStr);const zahl = 42;
let zahlStr = zahl.toString();
console.log(zahlStr, typeof zahlStr);Etwas unüblich aber durchaus in der Praxis zu finden ist der Einsatz des +-Operators zum Verketten von Zeichenketten:
zahlStr = '' + 17;
console.log(zahlStr, typeof zahlStr);zahlStr = '' + 17;
console.log(zahlStr, typeof zahlStr);Von Zeichenkette
const zahlwert = '1234';
const zahl1 = +zahlwert; // or Number
const zahl2 = parseInt(zahlwert); // or parseFloat
const zahl3 = Number(zahlwert);
const zahl4 = new Number(zahlwert);
console.log(zahl1, typeof zahl1);
console.log(zahl2, typeof zahl2);
console.log(zahl3, typeof zahl3);const zahlwert = '1234';
const zahl1 = +zahlwert; // or Number
const zahl2 = parseInt(zahlwert); // or parseFloat
const zahl3 = Number(zahlwert);
const zahl4 = new Number(zahlwert);
console.log(zahl1, typeof zahl1);
console.log(zahl2, typeof zahl2);
console.log(zahl3, typeof zahl3);Im Gegensatz zur Konstruktor-Semantik erzeugt also das einfache Aufrufen der
Number-Funktion einen primitiven Wert und kein Wrapper-Objekt.
Typ-Überprüfung
Das häufigste Szenario für die Überprüfung von Daten-Typen ist in Funktionen das Testen der Parameter. Ansonsten weiß der Programmierer in der Regel, welcher Typ in einer Variablen steckt.
Nicht übergebene Parameter
function printMessage(msg) {
if (typeof msg === 'undefined') {
msg = '(Empty Message)';
}
console.log(`Message: '${msg}'`);
}
printMessage('Hello World!');
printMessage();function printMessage(msg) {
if (typeof msg === 'undefined') {
msg = '(Empty Message)';
}
console.log(`Message: '${msg}'`);
}
printMessage('Hello World!');
printMessage();Der Vergleichsoperator
===wird im Abschnitt Syntax/Gleichheit erklärt.
Verschiedentlich wird auch (mit Bedacht) der logische Oder-Operator eingesetzt:
function printMessage(msg, options) {
if (typeof msg === 'undefined') {
msg = '(Empty Message)';
}
options = options || { withTimestamp: false };
console.log(`Message: '${msg}'`, options.withTimestamp);
}
printMessage('Hello World!');
printMessage('Hello JavaScript!', { withTimestamp: true });function printMessage(msg, options) {
if (typeof msg === 'undefined') {
msg = '(Empty Message)';
}
options = options || { withTimestamp: false };
console.log(`Message: '${msg}'`, options.withTimestamp);
}
printMessage('Hello World!');
printMessage('Hello JavaScript!', { withTimestamp: true });Zu den logischen Operatoren siehe Abschnitt Syntax/Logik-Operatoren.
Prüfung auf Zahl-Typ
function doubleValue(n) {
if (typeof n !== 'number') {
n = parseInt(n);
}
return n + n; // what about 2 * n?
}
doubleValue(17); // 34
doubleValue('31'); // 62
doubleValue('nix'); // ??function doubleValue(n) {
if (typeof n !== 'number') {
n = parseInt(n);
}
return n + n; // what about 2 * n?
}
doubleValue(17); // 34
doubleValue('31'); // 62
doubleValue('nix'); // ??Oder etwas kompakter mit der direkten Umwandlung aller Argumente:
function add(a,b) {
a = Number(a); b = Number(b);
return a + b;
}
add('17','4');function add(a,b) {
a = Number(a); b = Number(b);
return a + b;
}
add('17','4');
JavaScript Docs