static: was alle Objekte teilen
Kurz gesagt: Ein statisches Feld oder eine statische Methode gehört zur Klasse, nicht zum Objekt: Alle Objekte sehen einen gemeinsamen Wert, zum Beispiel einen Zähler der erzeugten Objekte.
Problem
Jedes Produkt ist Nr. 1
Der Shop will, dass jedes neue Produkt die nächste Nummer bekommt: 1, 2, 3… Du legst einen Zähler #nextId in die Klasse. Der Konstruktor gibt dem Produkt die aktuelle Nummer und erhöht den Zähler:
class Product { #nextId = 1; #id; #name;
constructor(name) { this.#name = name; this.#id = this.#nextId; this.#nextId++; }
toString() { return `Nr. ${this.#id} ${this.#name}`; }}
const bread = new Product("Brot");const milk = new Product("Milch");const coffee = new Product("Kaffee");console.log(String(bread));console.log(String(milk));console.log(String(coffee));Nr. 1 BrotNr. 1 MilchNr. 1 KaffeeAlle sind Nr. 1. Der Grund ist, dass #nextId ein Feld des Objekts ist, genau wie der Name. Jedes neue Produkt bekommt seinen eigenen Zähler, der bei 1 beginnt. Der Zähler des Brotes kommt nie bei der Milch an.
Die Idee
Ein Feld der Klasse, nicht des Objekts
Der Zähler gehört nicht zu einem Produkt. Alle Produkte teilen ihn sich. Füge static hinzu:
static #nextId = 1;Ein static-Feld ist ein Feld der Klasse. Es gibt eines, egal wie viele Objekte du erzeugst, und alle Objekte teilen es sich. Im Konstruktor erreichst du es über den Namen der Klasse: Product.#nextId.
class Product { static #nextId = 1; #id; #name;
constructor(name) { this.#name = name; this.#id = Product.#nextId; Product.#nextId++; }
toString() { return `Nr. ${this.#id} ${this.#name}`; }}
const bread = new Product("Brot");const milk = new Product("Milch");const coffee = new Product("Kaffee");console.log(String(bread));console.log(String(milk));console.log(String(coffee));Nr. 1 BrotNr. 2 MilchNr. 3 KaffeeDas Brot nimmt die 1 und macht den Zähler zu 2. Die Milch sieht denselben Zähler, nimmt die 2 und macht ihn zu 3.
static #nextId = 1;
constructor(name) { this.#name = name; this.#id = Product.#nextId; Product.#nextId++;}
const bread = new Product("Brot");const milk = new Product("Milch");const coffee = new Product("Kaffee");Schritt für Schritt, in Worten
- #nextId ist static: ein Feld in der Klasse, nicht eines in jedem Objekt.
- new Product("Brot"): ein neues Objekt. Der Konstruktor speichert den Namen.
- this.#id = Product.#nextId: Das Objekt nimmt die aktuelle Nummer, 1.
- Product.#nextId++ ändert den gemeinsamen Zähler: Jetzt ist er 2.
- Milch: derselbe Zähler. Es nimmt die 2 und macht ihn zu 3.
- Kaffee: Es nimmt die 3 und macht ihn zu 4.
- Es gibt einen Zähler für alle, deshalb sind die Nummern der Reihe nach.
Ein static-Feld ist über ein Objekt nicht sichtbar. Von außen erreichst du es über den Namen der Klasse (Order.count):
class Order { static count = 0;}
const order = new Order();console.log(Order.count, order.count);0 undefinedProbier es aus
Gemeinsam und eigen
Was gibt das Programm aus?
class Order { static count = 0; items = 0;
constructor() { Order.count++; this.items++; }}
const a = new Order();const b = new Order();const c = new Order();console.log(Order.count, c.items);count ist static: ein Zähler für alle Bestellungen, dreimal erhöht. items ist ein Feld des Objekts: Jede Bestellung hat ihr eigenes, einmal erhöht.Die Idee
Eine statische Methode: Arbeit ohne Objekt
Dasselbe gilt für Methoden. Eine static-Methode ist eine Methode der Klasse. Du rufst sie über den Namen der Klasse auf, ohne new:
class Calculator { static add(a, b) { return a + b; }
static average(values) { let sum = 0; for (const v of values) { sum += v; } return sum / values.length; }}
console.log(Calculator.add(10, 20));const grades = [5, 6, 4, 6];console.log(Calculator.average(grades));console.log(Math.max(3, 8));305.258Calculator.add braucht kein Objekt: Alles, was sie braucht, kommt als Parameter. Die Methoden von Math sind genauso: Math.max, Math.sqrt. Aus Math erzeugst du keine Objekte, und new Math() hält das Programm an:
TypeError: Math is not a constructorJavaScript hat kein main: Das Programm sind die Zeilen der Datei, von oben nach unten. Deshalb brauchten die Funktionen aus dem Modul „Funktionen“ keine Klasse.
Genauer, für Neugierige
Umgekehrt geht es auch: In einer static-Methode kannst du ein Objekt erzeugen und seine Methoden aufrufen.
Probier es aus
Finde den Fehler
Wähle die Zeile mit dem Fehler.
label() liest this.#name, und der Name gehört zu einem konkreten Produkt. Eine static-Methode gehört zur Klasse, also hat das Objekt tea gar keine solche Methode:TypeError: tea.label is not a functionstatic: Die Beschriftung gehört zum Produkt, also ist sie eine Instanzmethode.Die Idee
Konstanten
Die MwSt. ist für alle Produkte 20%, und sie ändert sich nicht, während das Programm läuft. So ein Wert ist eine Konstante:
const VAT_RATE = 0.20;
class Prices { static withVat(price) { return price * (1 + VAT_RATE); }}
console.log(Prices.withVat(50));console.log(`MwSt.: ${VAT_RATE * 100}%`);60MwSt.: 20%const bedeutet, dass die Variable einmal gesetzt wird und sich nicht ändern lässt. Du setzt sie außerhalb der Klasse, oben in die Datei. Die Namen von Konstanten schreibt man mit Großbuchstaben und Unterstrichen: VAT_RATE.
Wenn jemand versucht, sie zu ändern,
VAT_RATE = 0.25;hält das Programm an:
TypeError: Assignment to constant variable.Du gewinnst doppelt: Die Zahl 0.20 steht an einer Stelle mit einem klaren Namen, und niemand kann sie aus Versehen ändern.
Genauer, für Neugierige
Ein static-Feld in der Klasse ist keine Konstante: Es lässt sich von außen ändern.
class Prices { static VAT_RATE = 0.20;}
Prices.VAT_RATE = 0.25;console.log(Prices.VAT_RATE);0.25Manchmal ist der Wert für jedes Objekt anders, darf sich aber nach dem Erzeugen des Objekts nicht ändern. So ist die Nummer des Produkts. Mach sie zu einem privaten Feld mit einem Getter und ohne Setter (die Lektion „Kapselung“):
class Product { static #nextId = 1; #id; #name;
constructor(name) { this.#name = name; this.#id = Product.#nextId; Product.#nextId++; }
get id() { return this.#id; }}coffee.id liest die Nummer, und coffee.id = 5 ändert sie nicht: Das Feld #id ist privat und hat nur einen Getter.
Probier es aus
Was fehlt?
MONTHS = 12;const: Der Wert wird einmal gesetzt und lässt sich nicht ändern.Die Idee
Wann static und wann nicht
Frag dich: „Gehört das zu einem konkreten Objekt?“
- Ja (der Kontostand des Kontos, der Name des Produkts, das Abheben von einem Konto): ein Feld oder eine Methode des Objekts, ohne
static. - Nein (die Anzahl aller Konten, die MwSt., die Summe zweier Zahlen):
static.
Ein häufiger Fehler ist, alles static zu machen, damit du keine Objekte erzeugen musst. Dann teilen sich alle „Objekte“ dieselben Daten, und du bist wieder beim Problem mit den parallelen Arrays aus der ersten Lektion.
Übung
Was alle Objekte teilen
Löse die Aufgaben in deinem Editor.
1. Bestellungen. Eine Klasse Order mit Kunde und Betrag. Jede neue Bestellung bekommt die nächste Nummer aus einem statischen Zähler. Ein statischer Getter count sagt, wie viele Bestellungen erzeugt wurden.
const orders = [ new Order("Maria", 45.5), new Order("Peter", 120), new Order("Elena", 18.9),];for (const o of orders) { console.log(String(o));}console.log(`Bestellungen: ${Order.count}`);Bestellung Nr. 1: Maria, 45.5 €Bestellung Nr. 2: Peter, 120 €Bestellung Nr. 3: Elena, 18.9 €Bestellungen: 32. Taschenrechner. Eine Klasse Calculator mit statischen Methoden zum Addieren, Subtrahieren und Multiplizieren ganzer Zahlen und zum Dividieren von Dezimalzahlen.
console.log(Calculator.add(10, 20));console.log(Calculator.subtract(10, 15));console.log(Calculator.multiply(6, 7));console.log(Calculator.divide(5, 2));30-5422.53. Wechselstube. Eine Klasse Converter mit Konstanten für den Kurs: 1 € = 1,08 US-Dollar und 1 € = 0,85 britische Pfund (die Kurse sind Beispiele). Statische Methoden rechnen einen Betrag in Euro in Dollar und in Pfund um. Für 20 €:
20 EUR = 21.6 USD20 EUR = 17 GBPWeitere Aufgaben
- Nummerierte Konten. Gib dem
Accountaus der Lektion „Kapselung“ eine Kontonummer aus einem statischen Zähler und einen Getter ohne Setter für die Nummer. - Umrechnen in beide Richtungen. Gib
ConverterMethoden, die von Dollar und von Pfund in Euro umrechnen. Rechne 20 € in Dollar um und zurück in Euro. Bekommst du genau 20? - Ein Limit. Der Shop nimmt höchstens 3 Produkte in einem Warenkorb an. Füge dafür eine Konstante hinzu und lass die Methode zum Hinzufügen das vierte ablehnen.
Kurz gesagt
Das Modul in kurz
- Eine Klasse ist dein eigener Typ, und ein Objekt ist ein konkretes Exemplar davon, erzeugt mit
new. Die Variable zeigt auf das Objekt. Klassen und Objekte constructorsorgt dafür, dass das Objekt vollständig entsteht.thisist das aktuelle Objekt. Konstruktoren und this- Instanzmethoden arbeiten mit den Feldern des Objekts.
toString()sagt, wie es als Text aussieht. Instanzmethoden #-Felder sind privat. Von außen kommst du nur übergetundsetan sie, die prüfen. Kapselungstaticist das, was die Klasse teilt: Zähler und Hilfsmethoden. Konstanten sindconst.
Daten und Regeln an einer Stelle, die niemand umgehen kann: Das ist objektorientierte Programmierung. Im nächsten Modul fangen Klassen an, Code miteinander zu teilen.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Klassen und Objekte · Konstruktoren und this · Instanzmethoden · Kapselung
- Geht weiter in: OOP-Prinzipien · Werfen und eigene Exceptions · Reguläre Ausdrücke: Gruppen und Ersetzen · Daten in Dateien
- Aufgaben zum Thema: Klassen und Objekte