740 lines
14 KiB
Markdown
740 lines
14 KiB
Markdown
```markdown
|
||
---
|
||
title: JavaScript Tutorial (für Python-Erfahrene)
|
||
tags: [javascript, tutorial, beginner, programming]
|
||
created: 2026-03-27
|
||
---
|
||
|
||
# JavaScript Tutorial (für Python-Erfahrene)
|
||
|
||
Ziel: Du lernst JavaScript von Grund auf, aber mit Fokus auf das, was du als Python-Erfahrener schnell einordnen kannst. Viele Beispiele sind so gestaltet, dass du sie 1:1 nachbauen und variieren kannst.
|
||
|
||
---
|
||
|
||
## Inhaltsverzeichnis
|
||
1. [[#0 Wie führe ich JavaScript am besten aus]]
|
||
2. [[#1 Grundsyntax & Variablen]]
|
||
3. [[#2 Datentypen, Equality, Truthy/Falsy]]
|
||
4. [[#3 Strings & Template Literals]]
|
||
5. [[#4 Arrays (Listen) & Methoden]]
|
||
6. [[#5 Objekte (Dictionaries) & JSON]]
|
||
7. [[#6 Kontrollfluss (if, switch, Schleifen)]]
|
||
8. [[#7 Funktionen (inkl. Arrow Functions)]]
|
||
9. [[#8 Scope, Hoisting, Closures]]
|
||
10. [[#9 Module (import/export)]]
|
||
11. [[#10 Klassen & Prototypen]]
|
||
12. [[#11 Fehlerbehandlung (try/catch)]]
|
||
13. [[#12 Asynchronität: Event Loop, Promises, async/await]]
|
||
14. [[#13 DOM: Webseiten manipulieren]]
|
||
15. [[#14 Events (Click, Input, Delegation)]]
|
||
16. [[#15 Fetch API (HTTP), APIs, JSON]]
|
||
17. [[#16 Praktische Mini-Projekte]]
|
||
18. [[#17 Tooling: npm, Vite, Linting (kurz)]]
|
||
19. [[#18 Cheatsheet: Python vs. JavaScript]]
|
||
|
||
---
|
||
|
||
## 0) Wie führe ich JavaScript am besten aus?
|
||
|
||
### Option A — Browser-Konsole (schnell zum Experimentieren)
|
||
1. Öffne eine Website (z. B. `about:blank`)
|
||
2. DevTools öffnen:
|
||
- Chrome/Edge: `F12` oder `Ctrl+Shift+I`
|
||
- macOS: `Cmd+Opt+I`
|
||
3. Tab **Console** → JavaScript eintippen.
|
||
|
||
Beispiel:
|
||
```js
|
||
console.log("Hello JS!");
|
||
```
|
||
|
||
**Pro:** sofortiges Feedback
|
||
**Contra:** nicht so gut für größere Projekte
|
||
|
||
---
|
||
|
||
### Option B — HTML + `<script>` direkt im HTML (einfach)
|
||
Erstelle `index.html`:
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<title>JS Tutorial</title>
|
||
</head>
|
||
<body>
|
||
<h1>Hallo JavaScript</h1>
|
||
|
||
<script>
|
||
console.log("JS läuft!");
|
||
</script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
Öffne die Datei im Browser (Doppelklick) und dann DevTools → Console.
|
||
|
||
---
|
||
|
||
### Option C — HTML + externes `.js` File (empfohlen)
|
||
Das ist die gängigste Lern- und Projektstruktur.
|
||
|
||
`index.html`:
|
||
```html
|
||
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<title>JS Tutorial</title>
|
||
<script defer src="./main.js"></script>
|
||
</head>
|
||
<body>
|
||
<h1>Hallo JavaScript</h1>
|
||
<button id="btn">Klick mich</button>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
`main.js`:
|
||
```js
|
||
console.log("main.js geladen");
|
||
|
||
document.querySelector("#btn").addEventListener("click", () => {
|
||
console.log("Button geklickt");
|
||
});
|
||
```
|
||
|
||
**Wichtig:** `defer` sorgt dafür, dass das HTML zuerst geparst wird, bevor dein JS läuft (sehr praktisch für DOM-Skripte).
|
||
|
||
---
|
||
|
||
### Option D — Node.js (JavaScript außerhalb des Browsers)
|
||
Installiere Node.js (LTS). Dann im Terminal:
|
||
|
||
```bash
|
||
node -v
|
||
node
|
||
```
|
||
|
||
Oder Datei:
|
||
`app.js`:
|
||
```js
|
||
console.log("Hallo aus Node!");
|
||
```
|
||
|
||
Run:
|
||
```bash
|
||
node app.js
|
||
```
|
||
|
||
**Merke:** Browser-JS hat DOM/Web-APIs, Node hat dafür File-System etc.
|
||
|
||
---
|
||
|
||
## 1) Grundsyntax & Variablen
|
||
|
||
### `let`, `const`, (vermeide `var`)
|
||
```js
|
||
let x = 10; // kann neu zugewiesen werden
|
||
x = 11;
|
||
|
||
const y = 20; // darf nicht neu zugewiesen werden
|
||
// y = 21; // TypeError
|
||
|
||
const obj = { a: 1 };
|
||
obj.a = 2; // erlaubt! (Objektinhalt mutiert)
|
||
// obj = { a: 3 }; // nicht erlaubt (Neuzuweisung)
|
||
```
|
||
|
||
**Python-Vergleich:** `const` ist kein echtes Immutable wie `tuple`, sondern verhindert nur Reassignment der Variable.
|
||
|
||
---
|
||
|
||
## 2) Datentypen, Equality, Truthy/Falsy
|
||
|
||
### Primitive Typen
|
||
- `number` (integers + floats)
|
||
- `string`
|
||
- `boolean`
|
||
- `undefined`
|
||
- `null`
|
||
- `bigint`
|
||
- `symbol`
|
||
|
||
```js
|
||
let a; // undefined
|
||
let b = null; // absichtlich "leer"
|
||
```
|
||
|
||
### `==` vs `===` (wichtig)
|
||
- `===` vergleicht **ohne** Typumwandlung → nutze das fast immer
|
||
- `==` macht implizite Konvertierung → vermeide für Anfänger
|
||
|
||
```js
|
||
0 == false // true (komisch)
|
||
0 === false // false (gut/strikt)
|
||
|
||
"5" == 5 // true
|
||
"5" === 5 // false
|
||
```
|
||
|
||
### Truthy / Falsy
|
||
Falsy sind u. a.: `false`, `0`, `""`, `null`, `undefined`, `NaN`
|
||
|
||
```js
|
||
if ("") console.log("läuft nicht");
|
||
if ("0") console.log("läuft"); // nicht leerer String ist truthy
|
||
```
|
||
|
||
---
|
||
|
||
## 3) Strings & Template Literals
|
||
|
||
```js
|
||
const name = "Ada";
|
||
const age = 30;
|
||
|
||
console.log("Hallo " + name + ", du bist " + age);
|
||
console.log(`Hallo ${name}, du bist ${age}`); // Template Literal
|
||
```
|
||
|
||
Nützliche String-Methoden:
|
||
```js
|
||
"Hello".toUpperCase(); // "HELLO"
|
||
" hi ".trim(); // "hi"
|
||
"abc".includes("b"); // true
|
||
"1,2,3".split(","); // ["1","2","3"]
|
||
```
|
||
|
||
---
|
||
|
||
## 4) Arrays (Listen) & Methoden
|
||
|
||
```js
|
||
const nums = [1, 2, 3];
|
||
nums.push(4); // [1,2,3,4]
|
||
nums.pop(); // entfernt letztes
|
||
nums[0]; // 1
|
||
```
|
||
|
||
### Iteration
|
||
```js
|
||
for (const n of nums) {
|
||
console.log(n);
|
||
}
|
||
```
|
||
|
||
### `map`, `filter`, `reduce` (sehr wichtig)
|
||
```js
|
||
const doubled = nums.map(n => n * 2); // [2,4,6]
|
||
const evens = nums.filter(n => n % 2 === 0); // [2]
|
||
const sum = nums.reduce((acc, n) => acc + n, 0); // 6
|
||
```
|
||
|
||
**Python-Vergleich:** `map/filter/reduce` ähnlich, aber in JS extrem häufig in UI/Frontend.
|
||
|
||
---
|
||
|
||
## 5) Objekte (Dictionaries) & JSON
|
||
|
||
### Objekte (Key-Value)
|
||
```js
|
||
const user = {
|
||
name: "Ada",
|
||
age: 30,
|
||
isAdmin: true
|
||
};
|
||
|
||
console.log(user.name);
|
||
console.log(user["age"]);
|
||
```
|
||
|
||
### Dynamische Keys
|
||
```js
|
||
const key = "score";
|
||
const obj = { [key]: 42 };
|
||
console.log(obj.score); // 42
|
||
```
|
||
|
||
### Object Destructuring
|
||
```js
|
||
const { name, age } = user;
|
||
console.log(name, age);
|
||
```
|
||
|
||
### Spread (Kopieren/Mergen)
|
||
```js
|
||
const a = { x: 1, y: 2 };
|
||
const b = { ...a, y: 999, z: 3 }; // {x:1,y:999,z:3}
|
||
```
|
||
|
||
### JSON
|
||
```js
|
||
const json = JSON.stringify(user);
|
||
const parsed = JSON.parse(json);
|
||
```
|
||
|
||
---
|
||
|
||
## 6) Kontrollfluss (if, switch, Schleifen)
|
||
|
||
```js
|
||
const n = 7;
|
||
|
||
if (n > 10) {
|
||
console.log("groß");
|
||
} else if (n > 5) {
|
||
console.log("mittel");
|
||
} else {
|
||
console.log("klein");
|
||
}
|
||
```
|
||
|
||
### `switch`
|
||
```js
|
||
const role = "admin";
|
||
|
||
switch (role) {
|
||
case "admin":
|
||
console.log("Alles erlaubt");
|
||
break;
|
||
case "user":
|
||
console.log("Standardrechte");
|
||
break;
|
||
default:
|
||
console.log("Unbekannt");
|
||
}
|
||
```
|
||
|
||
### Schleifen
|
||
```js
|
||
for (let i = 0; i < 3; i++) console.log(i);
|
||
|
||
let i = 0;
|
||
while (i < 3) {
|
||
console.log(i);
|
||
i++;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7) Funktionen (inkl. Arrow Functions)
|
||
|
||
### Funktionsdeklaration
|
||
```js
|
||
function add(a, b) {
|
||
return a + b;
|
||
}
|
||
```
|
||
|
||
### Function Expression
|
||
```js
|
||
const add2 = function (a, b) {
|
||
return a + b;
|
||
};
|
||
```
|
||
|
||
### Arrow Function
|
||
```js
|
||
const add3 = (a, b) => a + b;
|
||
```
|
||
|
||
### Default-Parameter
|
||
```js
|
||
function greet(name = "Welt") {
|
||
return `Hallo ${name}`;
|
||
}
|
||
```
|
||
|
||
### Rest-Parameter
|
||
```js
|
||
function sum(...nums) {
|
||
return nums.reduce((acc, n) => acc + n, 0);
|
||
}
|
||
sum(1, 2, 3); // 6
|
||
```
|
||
|
||
---
|
||
|
||
## 8) Scope, Hoisting, Closures
|
||
|
||
### Block-Scope: `let/const`
|
||
```js
|
||
if (true) {
|
||
let x = 1;
|
||
}
|
||
// console.log(x); // ReferenceError
|
||
```
|
||
|
||
### Hoisting (vereinfachte Regel)
|
||
- `var` wird “hochgezogen” → vermeiden
|
||
- `let/const` existieren zwar “vorher”, sind aber in der **Temporal Dead Zone** → besser/strikter
|
||
|
||
### Closure
|
||
```js
|
||
function makeCounter() {
|
||
let count = 0;
|
||
return function () {
|
||
count++;
|
||
return count;
|
||
};
|
||
}
|
||
|
||
const c = makeCounter();
|
||
c(); // 1
|
||
c(); // 2
|
||
```
|
||
|
||
**Python-Vergleich:** ähnlich wie inner functions mit captured variables.
|
||
|
||
---
|
||
|
||
## 9) Module (import/export)
|
||
|
||
**Browser-Module**: In HTML:
|
||
```html
|
||
<script type="module" src="./main.js"></script>
|
||
```
|
||
|
||
`math.js`:
|
||
```js
|
||
export function add(a, b) {
|
||
return a + b;
|
||
}
|
||
|
||
export const PI = 3.14159;
|
||
```
|
||
|
||
`main.js`:
|
||
```js
|
||
import { add, PI } from "./math.js";
|
||
|
||
console.log(add(2, 3));
|
||
console.log(PI);
|
||
```
|
||
|
||
---
|
||
|
||
## 10) Klassen & Prototypen
|
||
|
||
### Klasse
|
||
```js
|
||
class User {
|
||
constructor(name) {
|
||
this.name = name;
|
||
}
|
||
|
||
greet() {
|
||
return `Hi ${this.name}`;
|
||
}
|
||
}
|
||
|
||
const u = new User("Ada");
|
||
console.log(u.greet());
|
||
```
|
||
|
||
### Vererbung
|
||
```js
|
||
class Admin extends User {
|
||
constructor(name) {
|
||
super(name);
|
||
this.role = "admin";
|
||
}
|
||
}
|
||
|
||
const a = new Admin("Grace");
|
||
```
|
||
|
||
**Merke:** JS ist prototyp-basiert; `class` ist syntactic sugar.
|
||
|
||
---
|
||
|
||
## 11) Fehlerbehandlung (try/catch)
|
||
|
||
```js
|
||
try {
|
||
JSON.parse("{ broken");
|
||
} catch (err) {
|
||
console.error("Parsing fehlgeschlagen:", err.message);
|
||
} finally {
|
||
console.log("läuft immer");
|
||
}
|
||
```
|
||
|
||
Eigene Fehler:
|
||
```js
|
||
function requirePositive(n) {
|
||
if (n <= 0) throw new Error("n muss > 0 sein");
|
||
return n;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 12) Asynchronität: Event Loop, Promises, async/await
|
||
|
||
### Warum async?
|
||
Im Browser soll UI nicht blockieren. In Node geht’s um I/O.
|
||
|
||
### Promise Basics
|
||
```js
|
||
const p = new Promise((resolve, reject) => {
|
||
setTimeout(() => resolve("fertig"), 500);
|
||
});
|
||
|
||
p.then(value => console.log(value));
|
||
```
|
||
|
||
### `async/await` (empfohlen)
|
||
```js
|
||
function wait(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
|
||
async function run() {
|
||
console.log("start");
|
||
await wait(300);
|
||
console.log("nach 300ms");
|
||
}
|
||
|
||
run();
|
||
```
|
||
|
||
### Parallel vs. sequenziell
|
||
```js
|
||
async function parallel() {
|
||
const p1 = wait(200);
|
||
const p2 = wait(300);
|
||
await Promise.all([p1, p2]);
|
||
console.log("beide fertig");
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 13) DOM: Webseiten manipulieren
|
||
|
||
### Elemente finden
|
||
```js
|
||
const h1 = document.querySelector("h1");
|
||
const items = document.querySelectorAll("li");
|
||
```
|
||
|
||
### Text/HTML ändern
|
||
```js
|
||
h1.textContent = "Neuer Titel";
|
||
h1.innerHTML = "<em>Kursiv</em>"; // vorsichtig (XSS bei fremden Daten!)
|
||
```
|
||
|
||
### Klassen und Styles
|
||
```js
|
||
h1.classList.add("highlight");
|
||
h1.style.color = "tomato";
|
||
```
|
||
|
||
### Elemente erstellen & anhängen
|
||
```js
|
||
const ul = document.querySelector("ul");
|
||
const li = document.createElement("li");
|
||
li.textContent = "Neues Item";
|
||
ul.appendChild(li);
|
||
```
|
||
|
||
---
|
||
|
||
## 14) Events (Click, Input, Delegation)
|
||
|
||
`index.html`:
|
||
```html
|
||
<input id="name" placeholder="Name" />
|
||
<button id="save">Speichern</button>
|
||
<div id="out"></div>
|
||
```
|
||
|
||
`main.js`:
|
||
```js
|
||
const input = document.querySelector("#name");
|
||
const btn = document.querySelector("#save");
|
||
const out = document.querySelector("#out");
|
||
|
||
btn.addEventListener("click", () => {
|
||
out.textContent = `Hallo ${input.value}`;
|
||
});
|
||
```
|
||
|
||
### Event Delegation (praktisch bei Listen)
|
||
```js
|
||
document.querySelector("#list").addEventListener("click", (e) => {
|
||
if (e.target.matches("li")) {
|
||
console.log("geklickt:", e.target.textContent);
|
||
}
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 15) Fetch API (HTTP), APIs, JSON
|
||
|
||
### GET Request
|
||
```js
|
||
async function loadTodo() {
|
||
const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
|
||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||
|
||
const data = await res.json();
|
||
console.log(data);
|
||
}
|
||
|
||
loadTodo().catch(console.error);
|
||
```
|
||
|
||
### POST Request
|
||
```js
|
||
async function createPost() {
|
||
const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ title: "Hi", body: "Text", userId: 1 })
|
||
});
|
||
|
||
const data = await res.json();
|
||
console.log("created:", data);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 16) Praktische Mini-Projekte
|
||
|
||
### Projekt 1: Counter
|
||
`index.html`:
|
||
```html
|
||
<h1 id="count">0</h1>
|
||
<button id="dec">-</button>
|
||
<button id="inc">+</button>
|
||
<button id="reset">reset</button>
|
||
<script defer src="./main.js"></script>
|
||
```
|
||
|
||
`main.js`:
|
||
```js
|
||
let count = 0;
|
||
|
||
const el = document.querySelector("#count");
|
||
const render = () => (el.textContent = String(count));
|
||
|
||
document.querySelector("#inc").addEventListener("click", () => {
|
||
count++;
|
||
render();
|
||
});
|
||
document.querySelector("#dec").addEventListener("click", () => {
|
||
count--;
|
||
render();
|
||
});
|
||
document.querySelector("#reset").addEventListener("click", () => {
|
||
count = 0;
|
||
render();
|
||
});
|
||
|
||
render();
|
||
```
|
||
|
||
### Projekt 2: Todo-Liste (minimal)
|
||
`index.html`:
|
||
```html
|
||
<input id="todo" placeholder="Neues Todo" />
|
||
<button id="add">Add</button>
|
||
<ul id="list"></ul>
|
||
<script defer src="./main.js"></script>
|
||
```
|
||
|
||
`main.js`:
|
||
```js
|
||
const input = document.querySelector("#todo");
|
||
const btn = document.querySelector("#add");
|
||
const list = document.querySelector("#list");
|
||
|
||
btn.addEventListener("click", () => {
|
||
const text = input.value.trim();
|
||
if (!text) return;
|
||
|
||
const li = document.createElement("li");
|
||
li.textContent = text;
|
||
list.appendChild(li);
|
||
|
||
input.value = "";
|
||
input.focus();
|
||
});
|
||
|
||
// Klick zum Entfernen (Delegation)
|
||
list.addEventListener("click", (e) => {
|
||
if (e.target.matches("li")) e.target.remove();
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 17) Tooling: npm, Vite, Linting (kurz)
|
||
|
||
Wenn du über “nur HTML+JS” hinaus willst (Module, Bundling, Dev-Server):
|
||
|
||
### Vite Setup
|
||
```bash
|
||
npm create vite@latest my-app
|
||
cd my-app
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
Das erstellt ein modernes Dev-Setup mit Hot Reload.
|
||
|
||
### Linting (optional)
|
||
- ESLint hilft, typische Fehler früh zu finden.
|
||
- Prettier formatiert Code automatisch.
|
||
|
||
---
|
||
|
||
## 18) Cheatsheet: Python vs. JavaScript
|
||
|
||
### Datenstrukturen
|
||
- Python `list` ≈ JS `Array`
|
||
- Python `dict` ≈ JS `Object` oder `Map`
|
||
- Python `None` ≈ JS `null` (oder `undefined` je nach Kontext)
|
||
|
||
### Funktionen
|
||
- Python: `def f(a=1): ...`
|
||
- JS: `function f(a = 1) { ... }` oder `(a = 1) => ...`
|
||
|
||
### Strings
|
||
- Python: `f"{x}"`
|
||
- JS: `` `${x}` ``
|
||
|
||
### Imports
|
||
- Python: `import x`
|
||
- JS (ESM): `import x from "./x.js"` / `import {a} from ...`
|
||
|
||
### Iteration
|
||
- Python: `for x in xs:`
|
||
- JS: `for (const x of xs) { ... }`
|
||
|
||
### Async
|
||
- Python: `async def`, `await`
|
||
- JS: `async function`, `await` (sehr ähnlich im Feeling, andere Runtime-Details)
|
||
|
||
---
|
||
|
||
## Nächste Schritte (Empfehlung)
|
||
1. Baue die Mini-Projekte nach und verändere sie (z. B. Todo: “erledigt” toggle statt löschen).
|
||
2. Übe `map/filter/reduce` auf Arrays mit echten Daten (z. B. aus `fetch`).
|
||
3. Wenn du Web-Apps willst: lerne danach ein Framework (React/Vue/Svelte) – aber erst, wenn DOM + async sitzen.
|
||
|
||
---
|
||
|
||
## Offene Fragen (damit ich das Tutorial besser anpassen kann)
|
||
- Willst du primär **Frontend im Browser** lernen oder auch **Node.js Backend**?
|
||
- Arbeitest du lieber mit **Vanilla JS** (ohne Framework) oder willst du schnell Richtung **React/Vue**?
|
||
```
|
||
|
||
Wenn du willst, kann ich daraus auch mehrere Obsidian-Notizen machen (z. B. „JS Basics“, „DOM“, „Async“, „Mini-Projekte“) und dir eine sinnvolle Link-Struktur (MOC) anlegen. |