Was ist JavaScript?
JavaScript ist eine Programmiersprache, die innerhalb einer Host-Umgebung ausgeführt wird und es Ihnen ermöglicht, die Abläufe auf einer Seite zu steuern. HTML liefert die Struktur, CSS die Darstellung und JavaScript das Verhalten. Wenn sich ein Menü öffnet, ein Formular validiert wird, eine Seite neue Daten ohne Neuladen lädt oder ein Spiel auf Ihre Tastatureingaben reagiert, erledigt JavaScript die Arbeit.
Es handelt sich um eine hochsprachige, dynamisch typisierte Multi-Paradigmen-Sprache. Vereinfacht gesagt bedeutet das: Sie müssen den Speicher nicht manuell verwalten, Sie müssen keine Typen im Voraus deklarieren und Sie können je nach Problemstellung in einem objektorientierten, funktionalen oder imperativen Stil schreiben.
Die Sprache wurde 1995 für eine einzige Aufgabe geschaffen – Webseiten ein wenig interaktiver zu machen – und ist längst aus diesem Rahmen herausgewachsen. Heute steuert dieselbe Syntax Server, mobile Apps, Command-Line-Tools und Desktop-Anwendungen. JavaScript zu lernen, ist eine der rentabelsten Investitionen, die Sie in der Webentwicklung tätigen können.
Wo JavaScript ausgeführt wird
JavaScript ist die Sprache. Eine Runtime ist die Umgebung, die diese ausführt. Die bekannteste Runtime ist der Browser, aber er ist bei weitem nicht die einzige.
- Browser liefern eine JavaScript-Engine mit (V8 in Chrome, SpiderMonkey in Firefox, JavaScriptCore in Safari) sowie Host-APIs wie das DOM,
fetch, Timer und Storage. - Node.js, Deno und Bun führen JavaScript auf dem Server aus und bieten APIs für Dateien, Netzwerke und Prozesse.
- Embedded Runtimes führen JavaScript in mobilen Apps, Desktop-Apps, Datenbanken und sogar auf Mikrocontrollern aus.
Die Sprache selbst ist als ECMAScript standardisiert. Das DOM, fetch und console sind nicht Teil der Sprache – es sind APIs, die von der Runtime bereitgestellt werden. Wenn man diese Unterscheidung im Hinterkopf behält, wird klar, warum derselbe Code in einer Umgebung funktioniert und in einer anderen nicht.
Variablen: let, const und var
Eine Variable ist eine benannte Referenz auf einen Wert. Modernes JavaScript bietet drei Möglichkeiten, eine solche zu erstellen, aber Sie benötigen nur zwei davon.
// app.js
const name = "Ada"; // cannot be reassigned
let score = 0; // can be reassigned
score = score + 10;
// var is the legacy form — avoid it in new code
var old = true;
Verwenden Sie standardmäßig const. Dies macht den Wert nicht unveränderlich (immutable) – Sie können die Inhalte eines const-Objekts oder Arrays weiterhin mutieren –, es verhindert lediglich, dass der Name einem anderen Wert neu zugewiesen wird. Verwenden Sie let, wenn sich ein Wert tatsächlich ändert, wie zum Beispiel bei einem Zähler oder Akkumulator. Greifen Sie nur dann auf var zurück, wenn Sie alten Code lesen.
Datentypen
JavaScript verfügt über eine kleine Auswahl an primitiven Typen sowie Objekte.
| Typ | Beispiel | Notizen |
|---|---|---|
| string | "hello" |
Text, einfache oder doppelte Anführungszeichen oder Backticks |
| number | 42, 3.14 |
Ein numerischer Typ für Integer und Floats |
| bigint | 9007199254740993n |
Beliebig große Ganzzahlen |
| boolean | true, false |
Logische Werte |
| undefined | undefined |
Ein deklarierter, aber nicht zugewiesener Wert |
| null | null |
Ein beabsichtigtes Fehlen eines Wertes |
| symbol | Symbol("id") |
Eindeutige Identifikatoren |
| object | { name: "Ada" } |
Collections, Funktionen, Arrays — alles andere |
Der typeof-Operator verrät dir, womit du es zu tun hast. Achte auf zwei bekannte Eigenheiten: typeof null ist "object" (ein historischer Bug, der aus Kompatibilitätsgründen beibehalten wurde) und typeof eine Funktion ist "function", obwohl Funktionen eigentlich Objekte sind.
Funktionen
Funktionen sind wiederverwendbare Logikblöcke und in JavaScript sind sie Werte. Du kannst sie in Variablen speichern, als Argumente übergeben und aus anderen Funktionen zurückgeben.
// greet.js
function greet(name) {
return `Hello, ${name}!`;
}
const add = (a, b) => a + b;
const shout = (text) => text.toUpperCase();
Die Deklarationsform function wird gehoisted und kann daher aufgerufen werden, bevor sie im Code erscheint. Arrow functions (=>) sind kürzer, besitzen kein eigenes this und sind ideal für Callbacks. Wenn eine Funktion nur einen einzigen Ausdruck enthält, können der Funktionskörper und das return weggelassen werden.
Funktionen können zudem Default-Parameter haben und über die Rest-Syntax eine variable Anzahl an Argumenten akzeptieren:
// math.js
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
function greet(name = "friend") {
return `Hi, ${name}`;
}
sum(1, 2, 3); // 6
Objekte und Arrays
Objekte speichern benannte Werte; Arrays speichern geordnete Werte. Zusammen bilden sie fast jedes Datenstück ab, mit dem du arbeiten wirst.
// data.js
const user = {
name: "Ada",
age: 36,
admin: true,
};
const skills = ["HTML", "CSS", "JavaScript"];
user.name; // "Ada"
skills.length; // 3
skills[0]; // "HTML"
Du kannst beide destrukturieren, um Werte sauber zu extrahieren, und sie mit dem Spread-Operator kopieren:
// destructure.js
const { name, age } = user;
const [first, ...rest] = skills;
const updated = { ...user, age: 37 };
const moreSkills = [...skills, "TypeScript"];
Objekte und Arrays sind Referenztypen. Wenn du eines davon einer anderen Variable zuweist, wird die Referenz kopiert, nicht der Inhalt. Das bedeutet, dass eine Mutation über einen der beiden Namen denselben zugrunde liegenden Wert ändert. Der Spread-Operator erstellt eine flache Kopie (shallow copy), wenn du Unabhängigkeit benötigst.
Kontrollfluss
Bedingungen und Schleifen steuern den Ablauf Ihres Programms.
// logic.js
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else {
grade = "C";
}
for (const skill of skills) {
console.log(skill);
}
Bevorzugen Sie for...of für Arrays und for...in nur für das Aufzählen von Objektschlüsseln. Der Ternary-Operator condition ? a : b ist ein kompakter Ausdruck, wenn Sie einen Wert benötigen und keinen Branch mit Seiteneffekten. Der Nullish Coalescing Operator ?? und Optional Chaining ?. machen defensiven Code lesbar:
// safe.js
const city = user.address?.city ?? "Unknown";
Scope und Closures
Scope (Geltungsbereich) definiert, wo eine Variable sichtbar ist. Ein Block { } erzeugt einen Scope für let und const. Eine Funktion erzeugt einen Scope für alles, was sich in ihr befindet. Closures sind die Folge daraus: Eine innere Funktion behält den Zugriff auf die Variablen der äußeren Funktion, selbst nachdem diese Funktion bereits zurückgegeben wurde.
// counter.js
function createCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const next = createCounter();
next(); // 1
next(); // 2
Die zurückgegebene Funktion “schließt” count ein (closes over), wodurch diese Variable lebendig und privat bleibt. Closures sind die Basis für Event-Handler, Memoisation, Currying und Modul-Patterns. Sie gehören zu den wichtigsten Konzepten der Sprache, und sobald man sie verstanden hat, ergibt vieles in JavaScript plötzlich Sinn.
Der Event Loop: Ein erster Einblick
JavaScript führt Ihren Code in einem einzigen Thread aus – es kann also immer nur eine Sache gleichzeitig erledigen. Dennoch friert die Anwendung nicht ein, während sie auf eine Netzwerkanfrage wartet. Das Geheimnis ist der Event Loop.
Synchroner Code wird sofort auf dem Call Stack ausgeführt. Wenn Sie etwas Asynchrones planen, wie etwa einen Timer oder einen Fetch, übergibt die Runtime diese Aufgabe und macht direkt weiter. Sobald die Aufgabe abgeschlossen ist, wird ihr Callback in eine Queue eingereiht. Der Event Loop arbeitet die Queue erst dann ab, wenn der Stack leer ist.
// loop.js
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
// Output: 1, 3, 2
Selbst bei einer Verzögerung von null Millisekunden wartet der Callback, bis der aktuelle synchrone Code beendet ist. Diese Reihenfolge ist die Grundlage für Promises und async/await, welche im Async JavaScript Guide ausführlich behandelt werden.
So fügst du JavaScript zu einer Seite hinzu
Du bindest JavaScript mithilfe eines <script>-Elements in HTML ein. Platziere es am Ende des Body-Bereichs oder verwende das defer-Attribut, damit das HTML geparst wird, bevor dein Code ausgeführt wird.
<!-- index.html -->
<body>
<h1>Hello</h1>
<script src="app.js" defer></script>
</body>
Inline-Skripte funktionieren ebenfalls, aber externe Dateien sind cachebar, wiederverwendbar und einfacher zu debuggen. Nutze type="module", um ES-Module mit import und export zu laden.
Häufige Fehler
- Verwendung von
varund Überraschung über Hoisting oder Function Scope. - Vergleiche mit
==, die zu unerwarteter Typumwandlung (Type Coercion) führen. Nutze stattdessen===. - Mutation eines Objekts oder Arrays in der Annahme, es sei eine Kopie erstellt worden.
- Die Tatsache zu vergessen, dass
thisdavon abhängt, wie eine Funktion aufgerufen wird, und nicht davon, wo sie definiert wurde. nullundundefinedohne ersichtlichen Grund als austauschbar zu betrachten.- Zu früh zu einem Framework zu greifen, bevor einfache Funktionen und Objekte verstanden wurden.
Best Practices
- Bevorzuge
const, dannletund vermeidevar. - Nutze immer
===und!==, es sei denn, du möchtest explizit eine Coercion. - Halte Funktionen klein und konzentriere sie auf eine einzige Aufgabe.
- Benenne Dinge nach ihrer Bedeutung, nicht nach ihrem Typ.
- Nutze Optional Chaining und Nullish Coalescing für einen sicheren Zugriff.
- Lerne zuerst die Sprache und dann das Framework. Grundlagen überdauern Tools.
Was du als Nächstes lernen solltest
Du hast nun das grundlegende mentale Modell verinnerlicht: Werte, Variablen, Funktionen, Objekte, Scope und den Event Loop. Die nächsten logischen Schritte sind das DOM für die Interaktion mit Webseiten, ES6+ Features für die moderne Syntax und asynchrones JavaScript für Promises und async/await. Such dir eines davon aus, baue ein kleines Projekt und lass die praktische Erfahrung wachsen.