JavaScript ist eine dynamisch typisierte Sprache, in der Variablen ohne explizite Typdeklaration verwendet werden können. Diese Flexibilität bietet einerseits Freiheiten bei der Entwicklung, erfordert andererseits aber auch ein tiefes Verständnis der zugrundeliegenden Mechanismen, um häufige Fehlerquellen zu vermeiden.
In JavaScript können Variablen auf unterschiedliche Weise deklariert werden:
// var - funktionsweiter Scope (veraltet)
var counter = 42;
// let - blockweiter Scope (empfohlen)
let username = "developer";
// const - unveränderliche Referenz (empfohlen für Werte, die sich nicht ändern)
const PI = 3.14159;Die Verwendung von let und const
(eingeführt mit ES6) ist der älteren var-Deklaration
vorzuziehen, da sie ein vorhersehbareres Verhalten durch ihren
Block-Scope bieten. Hierdurch werden auch viele der klassischen Probleme
mit Variablen-Hoisting vermieden, auf die wir im Kapitel “Funktionen,
Scopes und Closures” näher eingehen werden.
JavaScript kennt sieben primitive Datentypen:
// Number - Fließkommazahlen und Ganzzahlen
let count = 42;
let price = 9.99;
let infinity = Infinity;
let notANumber = NaN;
// String - Textdaten
let greeting = "Hallo Welt";
let multiline = `Dies ist ein
mehrzeiliger Text`; // Template-Strings (ES6)
// Boolean - Wahrheitswerte
let isActive = true;
// Undefined - Deklarierte, aber nicht initialisierte Variable
let undefinedVar;
// Null - Absichtliche Abwesenheit eines Wertes
let emptyValue = null;
// Symbol - Eindeutige, unveränderliche Werte (ES6)
let uniqueKey = Symbol('id');
// BigInt - Ganzzahlen mit beliebiger Präzision (ES11)
let bigNumber = 9007199254740991n;Eine Besonderheit von JavaScript ist die Möglichkeit, den Datentyp einer Variable während der Laufzeit zu ändern:
let value = 42; // Number
value = "42"; // jetzt ein String
value = true; // jetzt ein BooleanDiese Flexibilität kann vorteilhaft sein, birgt aber auch Risiken hinsichtlich der Codequalität und Wartbarkeit. In größeren Projekten empfiehlt sich daher oft der Einsatz von TypeScript (siehe Kapitel “TypeScript als JavaScript-Superset”), um statische Typisierung einzuführen.
Neben den primitiven Datentypen gibt es in JavaScript Referenztypen, die komplexere Datenstrukturen ermöglichen:
// Object - Sammlung von Eigenschaften
let person = {
name: "Max Mustermann",
age: 30,
isActive: true
};
// Array - Geordnete Liste von Werten
let colors = ["Rot", "Grün", "Blau"];
// Function - Ausführbarer Code
let greet = function(name) {
return `Hallo ${name}`;
};
// RegExp - Reguläre Ausdrücke
let pattern = /^\d{5}$/;
// Date - Datums- und Zeitobjekte
let now = new Date();
// Map, Set, WeakMap, WeakSet (ES6)
let userRoles = new Map();
let uniqueIDs = new Set();Um den Typ einer Variable zu ermitteln, stehen verschiedene Methoden zur Verfügung:
// typeof-Operator
typeof 42; // "number"
typeof "text"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (historischer Fehler in JavaScript)
typeof {}; // "object"
typeof []; // "object" (Arrays sind in JavaScript Objekte)
typeof function() {}; // "function"
// instanceof-Operator für Referenztypen
[] instanceof Array; // true
new Date() instanceof Date; // true
// Array.isArray() für Arrays
Array.isArray([]); // trueDie Besonderheit, dass typeof null den Wert
"object" zurückgibt, ist ein bekannter Fehler in
JavaScript, der aus Kompatibilitätsgründen nie behoben wurde.
JavaScript führt in vielen Situationen automatische Typkonvertierungen durch, insbesondere bei Vergleichen und Operationen mit unterschiedlichen Datentypen.
// String + Number = String
"5" + 3; // "53"
// Boolean + Number = Number
true + 1; // 2 (true wird zu 1 konvertiert)
// Boolean + String = String
true + "test"; // "truetest"
// Vergleiche mit ==
5 == "5"; // true (Wertgleichheit mit Typkonvertierung)
0 == ""; // true (leerer String wird zu 0 konvertiert)
0 == false; // true (false wird zu 0 konvertiert)Diese automatischen Konvertierungen können zu unerwartetem Verhalten
führen. Daher ist es empfehlenswert, stets den strikten
Vergleichsoperator === zu verwenden, der keine
Typkonvertierung durchführt:
5 === "5"; // false (unterschiedliche Typen)
0 === ""; // false
0 === false; // falseFür präzisere Kontrolle über Typkonvertierungen bietet JavaScript verschiedene explizite Methoden:
// Zu String konvertieren
String(42); // "42"
(42).toString(); // "42"
42 + ""; // "42" (implizite Konvertierung)
// Zu Number konvertieren
Number("42"); // 42
parseInt("42px"); // 42 (extrahiert Zahlen am Anfang)
parseFloat("3.14"); // 3.14
+"42"; // 42 (unärer Plus-Operator)
// Zu Boolean konvertieren
Boolean(1); // true
Boolean(0); // false
Boolean(""); // false
Boolean("text"); // true
!!42; // true (doppelte Negation)In JavaScript werden Werte in booleschen Kontexten (z.B. in if-Anweisungen) automatisch in true oder false konvertiert:
// Falsy-Werte - werden zu false konvertiert
if (false) {} // false
if (0) {} // false
if ("") {} // false
if (null) {} // false
if (undefined) {} // false
if (NaN) {} // false
// Truthy-Werte - werden zu true konvertiert
if (true) {} // true
if (42) {} // true
if ("text") {} // true
if ({}) {} // true
if ([]) {} // true
if (function() {}) {} // trueDiese Eigenschaft wird häufig für Kurzschlussauswertungen genutzt:
// Standardwert zuweisen, wenn Variable undefined ist
let username = userInput || "Gast";
// Funktion nur ausführen, wenn sie existiert
callback && callback();=== und !== statt
== und !=, um unerwartete Typkonvertierungen
zu vermeiden.NaN === NaN
ist false, verwenden Sie stattdessen isNaN()
oder besser Number.isNaN().0.1 + 0.2 !== 0.3.// Probleme mit Fließkommazahlen
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// Lösungsansatz für präzise Vergleiche
function isApproximatelyEqual(a, b, epsilon = 0.0001) {
return Math.abs(a - b) < epsilon;
}
console.log(isApproximatelyEqual(0.1 + 0.2, 0.3)); // true