it-praxisportal/courses/javascript/03_funktionen_und_scope/README.md

7 KiB
Raw Blame History

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):

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:

const verdopple = function(x) {
  return x * 2;
};

3. Arrow Function (Pfeilfunktion / ES6)

Kompakte Syntax, kein eigenes this oder arguments-Objekt:

// 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:

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:

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.

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:

# Im Browser:
workspace.html?course=javascript&track=track_1_grundlagen&chapter=03_funktionen_und_scope