173 lines
7 KiB
Markdown
173 lines
7 KiB
Markdown
# JS 03: Funktionen, Gültigkeitsbereiche (Scope) & Closures 🔐
|
||
|
||
Willkommen zu **Modul 03** des JavaScript-Kurses!
|
||
|
||
In JavaScript sind Funktionen sogenannte **First-Class Citizens**: Sie können wie gewöhnliche Variablen gespeichert, als Argumente übergeben und von anderen Funktionen zurückgegeben werden (*Higher-Order Functions*).
|
||
|
||
In diesem Modul meisterst du moderne Funktionsarten, Gültigkeitsbereiche (*Scopes*) und eines der faszinierendsten Kernkonzepte von JavaScript: **Closures**!
|
||
|
||
---
|
||
|
||
## 💡 1. Das Wichtigste in Kürze
|
||
|
||
### A. Funktionsarten im Vergleich
|
||
|
||
#### 1. Function Declaration (Klassische Funktionsdeklaration)
|
||
Wird vollständig gehoistet (kann bereits vor ihrer Definition im Code aufgerufen werden):
|
||
|
||
```javascript
|
||
console.log(quadriere(4)); // 16 (funktioniert dank Hoisting!)
|
||
|
||
function quadriere(x) {
|
||
return x * x;
|
||
}
|
||
```
|
||
|
||
#### 2. Function Expression (Funktionsausdruck)
|
||
Wird einer Variablen zugewiesen und ist erst ab der Zuweisungszeile verfügbar:
|
||
|
||
```javascript
|
||
const verdopple = function(x) {
|
||
return x * 2;
|
||
};
|
||
```
|
||
|
||
#### 3. Arrow Function (Pfeilfunktion / ES6)
|
||
Kompakte Syntax, kein eigenes `this` oder `arguments`-Objekt:
|
||
|
||
```javascript
|
||
// Ausführliche Arrow Function:
|
||
const addiere = (a, b) => {
|
||
return a + b;
|
||
};
|
||
|
||
// Einzeilige Arrow Function mit implizitem Return:
|
||
const multipliziere = (a, b) => a * b;
|
||
```
|
||
|
||
---
|
||
|
||
### B. Moderne Parameter: Default- & Rest-Parameter
|
||
|
||
#### 1. Default-Parameter (Standardwerte)
|
||
Verhindert `undefined`, wenn kein Wert übergeben wird:
|
||
|
||
```javascript
|
||
function begruesse(name = "Gast", sprache = "de") {
|
||
return sprache === "de" ? `Hallo, ${name}!` : `Hello, ${name}!`;
|
||
}
|
||
|
||
console.log(begruesse()); // "Hallo, Gast!"
|
||
console.log(begruesse("Anna", "en")); // "Hello, Anna!"
|
||
```
|
||
|
||
#### 2. Rest-Parameter (`...rest`)
|
||
Sammelt eine beliebige Anzahl von Argumenten in einem echten JavaScript-Array:
|
||
|
||
```javascript
|
||
function maxZahl(...zahlen) {
|
||
// 'zahlen' ist ein echtes Array!
|
||
return Math.max(...zahlen);
|
||
}
|
||
|
||
console.log(maxZahl(3, 9, 21, 4)); // 21
|
||
```
|
||
|
||
---
|
||
|
||
### C. Gültigkeitsbereiche (Scopes) & Hoisting
|
||
|
||
JavaScript kennt drei Ebenen von Scopes:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ 🌍 GLOBAL SCOPE (Überall im Programm sichtbar) │
|
||
│ const globalVar = "Welt"; │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────┐ │
|
||
│ │ 📦 FUNCTION SCOPE (Nur innerhalb der Funktion) │ │
|
||
│ │ function meineFunktion() { │ │
|
||
│ │ const funcVar = "Funktion"; │ │
|
||
│ │ │ │
|
||
│ │ ┌───────────────────────────────────────┐ │ │
|
||
│ │ │ 🔒 BLOCK SCOPE (if, for, { let/const})│ │ │
|
||
│ │ │ if (true) { │ │ │
|
||
│ │ │ const blockVar = "Block"; │ │ │
|
||
│ │ │ } │ │ │
|
||
│ │ └───────────────────────────────────────┘ │ │
|
||
│ │ } │ │
|
||
│ └─────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- **`let` und `const`** besitzen **Block-Scope** (gelten nur innerhalb der `{ ... }` geschweiften Klammern).
|
||
- **`var`** besitzt nur **Function-Scope** (ignoriert `if`- und `for`-Blöcke) und sollte in modernem JS vermieden werden.
|
||
- **Lexical Scope (Statische Bindung):** Innere Funktionen können auf Variablen ihrer äußeren Eltern-Scopes zugreifen, aber nicht umgekehrt!
|
||
|
||
---
|
||
|
||
### D. Closures: Das Super-Feature
|
||
|
||
> **Definition Closure:** Eine Closure entsteht, wenn eine innere Funktion Zugriff auf Variablen ihres äußeren Gültigkeitsbereichs behält – **selbst nachdem die äußere Funktion ihre Ausführung längst beendet hat**.
|
||
|
||
```javascript
|
||
function erstelleSparschwein() {
|
||
let guthaben = 0; // Private Variable, von außen nicht direkt änderbar!
|
||
|
||
return function(einzahlung) {
|
||
guthaben += einzahlung;
|
||
return `Aktuelles Guthaben: ${guthaben} €`;
|
||
};
|
||
}
|
||
|
||
const meinKonto = erstelleSparschwein();
|
||
console.log(meinKonto(50)); // "Aktuelles Guthaben: 50 €"
|
||
console.log(meinKonto(100)); // "Aktuelles Guthaben: 150 €"
|
||
|
||
// Wichtig: 'guthaben' kann von außen nicht manipuliert werden (z.B. kein meinKonto.guthaben = 0)!
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Die didaktische Analogie: "Der Tresor mit Geheimzahl"
|
||
|
||
Stelle dir eine Closure wie einen **verschlossenen Tresor mit einem Einwurf-Schlitz und Zahlenrad** vor:
|
||
|
||
- **Der Erbauer (Die äußere Factory-Funktion):**
|
||
Die äußere Funktion baut den Tresor und legt die interne Mechanik (die geschützten Variablen `let zaehler`) im Inneren des Gehäuses an.
|
||
- **Der Schlüsselanhänger (Die zurückgegebene innere Funktion):**
|
||
Du erhältst von der Funktion lediglich den Schlüssel (die Referenz auf die innere Funktion).
|
||
- **Geschützte Kapselung (Data Encapsulation):**
|
||
Niemand von außen kann die Tresorwand aufbrechen oder direkt an die internen Zahnräder fassen. Nur wenn du den Schlüssel drehst (`zaehler()`), verändert sich der interne Zählerstand kontrolliert.
|
||
- **Unabhängige Instanzen:**
|
||
Jeder neue Aufruf der äußeren Funktion baut einen komplett eigenständigen Tresor. Tresor A und Tresor B beeinflussen sich gegenseitig zu keinem Zeitpunkt!
|
||
|
||
---
|
||
|
||
## 🎯 Aufgaben & Teilziele in `aufgabe.js`
|
||
|
||
Öffne die Datei `aufgabe.js` und implementiere folgende 4 Funktionen:
|
||
|
||
1. **TODO 1: `erstelleZaehler(startWert = 0)`**
|
||
Gibt eine Zählerfunktion (Closure) zurück. Jeder Aufruf erhöht den internen Zähler um 1 und gibt den neuen Stand zurück.
|
||
|
||
2. **TODO 2: `multiplizierer(faktor)`**
|
||
Erzeugt eine Multiplikator-Funktion (Closure): `(x) => x * faktor`.
|
||
*Beispiel:* `const verdopple = multiplizierer(2); verdopple(5); // 10`
|
||
|
||
3. **TODO 3: `summiereAlles(...zahlen)`**
|
||
Nimmt beliebig viele Zahlen per Rest-Parameter entgegen und gibt deren Gesamtsumme zurück. Bei leerem Aufruf wird `0` zurückgegeben.
|
||
|
||
4. **TODO 4: `erstellePraefixierer(praefix)`**
|
||
Gibt eine Funktion (Closure) zurück, die vor jeden übergebenen String das vorgegebene `praefix` anhängt: `(text) => `${praefix}${text}``.
|
||
|
||
---
|
||
|
||
## 🧪 Tests ausführen
|
||
|
||
Öffne die Web-IDE oder führe die Testsuite aus:
|
||
|
||
```bash
|
||
# Im Browser:
|
||
workspace.html?course=javascript&track=track_1_grundlagen&chapter=03_funktionen_und_scope
|
||
```
|