Zum Inhalt
wannacode

Instanzmethoden

Kurz gesagt: Eine Instanzmethode ist eine Funktion in der Klasse, die über this mit den Daten des Objekts arbeitet, und toString sagt, wie das Objekt zu Text wird.

Problem

Jeder hebt auf seine Art ab

Die Bank hat eine Klasse Account mit Inhaber und Kontostand. An zwei Stellen im Programm wird Geld abgehoben. Der Geldautomat prüft, ob genug Geld da ist. Die Kartenzahlung hat jemand anderes geschrieben, und sie prüft nicht:

const account = new Account("Maria", 100);
// Der Geldautomat prüft, ob genug Geld da ist.
if (account.balance >= 70) {
account.balance -= 70;
}
// Die Kartenzahlung hat jemand anderes geschrieben, und eine Prüfung gibt es nicht.
account.balance -= 50;
console.log(account.balance);
Ausgabe
-20

Das Konto ist im Minus. Die Regel „Du kannst nicht mehr abheben, als du hast“ ist wichtig, aber sie steht (oder fehlt) an jeder Stelle, die abhebt, einzeln.

Die Idee

Methoden wohnen bei den Daten

Die Logik des Abhebens gehört zum Konto, also kommt sie in die Klasse Account. Eine Funktion, die in der Klasse steht, ist eine Methode des Objekts:

bank.js
class Account {
owner;
balance;
constructor(owner, balance) {
this.owner = owner;
this.balance = balance;
}
deposit(amount) {
this.balance += amount;
}
withdraw(amount) {
if (amount <= this.balance) {
this.balance -= amount;
} else {
console.log(`Nicht genug Geld: ${this.owner}`);
}
}
}
const account = new Account("Maria", 100);
account.withdraw(70);
account.withdraw(50);
account.deposit(20);
console.log(account.balance);
Ausgabe
Nicht genug Geld: Maria
50
  • Du schreibst die Methode in der Klasse ohne das Wort function: withdraw(amount) { … }.
  • Du rufst sie mit einem Punkt auf einem Objekt auf: account.withdraw(70), genau wie die Felder.
  • Innen ist this.balance der Kontostand dieses Kontos, des Objekts vor dem Punkt. Das this. ist Pflicht: Ohne es ist balance nicht das Feld.
  • Die Prüfung steht einmal da. Wer über die Methode abhebt, geht durch sie hindurch.

const maria = new Account("Maria", 100);
const peter = new Account("Peter", 40);
maria.withdraw(70);
peter.withdraw(70);
console.log(maria.balance, peter.balance);
Schritt für Schritt, in Worten
  1. Zwei Konten, zwei Objekte. Jedes hat seinen eigenen Kontostand.
  2. maria.withdraw(70): this bekommt einen Pfeil auf das Objekt vor dem Punkt.
  3. In der Methode ist this.balance der Kontostand von Maria: 100 - 70 = 30.
  4. Dieselbe Methode, ein anderes Objekt: Jetzt zeigt this auf Peter.
  5. 70 ist mehr als 40: Die Methode gibt eine Ablehnung aus, und der Kontostand von Peter bleibt gleich.
  6. Den Code der Methode gibt es einmal. Die Felder gehören dem Objekt, auf dem du sie aufrufst.

Die Kartenzahlung kann die Prüfung nicht mehr „vergessen“, wenn sie mit withdraw abhebt. Sie kann aber immer noch direkt ins Feld schreiben. Wie du das verhinderst, siehst du in der Lektion „Kapselung“.

Die Idee

Methode oder Funktion

Die Funktionen aus dem Modul „Funktionen“ stehen außerhalb der Klasse. Sie bekommen alles als Parameter und haben kein eigenes Objekt. Eine Methode arbeitet mit den Feldern des Objekts, auf dem sie aufgerufen wurde:

function applyDiscount(price, percent) {
return price * (100 - percent) / 100;
}
const price = applyDiscount(10, 10);
account.withdraw(70);

Eine Instanzmethode kannst du nicht über den Namen der Klasse aufrufen. Es ist nicht klar, von welchem Konto abgehoben werden soll:

Account.withdraw(70);
Fehler
TypeError: Account.withdraw is not a function

Die Methode withdraw gehört zu den Objekten, nicht zur Klasse Account selbst. Klassenmethoden gibt es auch: Sie haben static davor. Du siehst sie in der Lektion „static: was alle Objekte teilen“.

Probier es aus

Wessen Konto?

Was gibt das Programm aus?

const maria = new Account("Maria", 100);
const peter = new Account("Peter", 40);
maria.deposit(30);
peter.withdraw(10);
console.log(maria.balance, peter.balance);
Antwort

Probier es aus

Finde den Fehler

account.withdraw(30) hält das Programm mit einem Fehler an. In welcher Zeile ist der Fehler?

Wähle die Zeile mit dem Fehler.

Die Idee

Eine Methode kann auch antworten

Eine Instanzmethode kann ein Ergebnis zurückgeben, genau wie die Funktionen aus dem Modul „Funktionen“. Ein Produkt kennt seinen Preis und seine Stückzahl, also kann es dir seine eigenen Kosten sagen:

class Product {
// die Felder und der Konstruktor, wie vorher
total() {
return this.price * this.quantity;
}
}
const cart = [
new Product("Brot", 1.20, 2),
new Product("Milch", 2.10, 1),
new Product("Kaffee", 7.50, 1),
];
let sum = 0;
for (const p of cart) {
sum += p.total();
}
console.log(`Gesamt: ${sum} €`);
Ausgabe
Gesamt: 12 €

Vergleich das mit der ersten Lektion des Moduls: Dort wurde die Summe in dem Code unter der Klasse aus den Feldern berechnet. Jetzt fragt dieser Code nur noch jedes Produkt. Kommt morgen ein Mengenrabatt dazu, änderst du nur total().

Die Idee

Wie sieht das Objekt als Text aus?

Wenn du ein Produkt direkt ausgibst, bekommst du etwas Nutzloses:

const coffee = new Product("Kaffee", 7.50, 1);
console.log(`Einkauf: ${coffee}`);
console.log(coffee);
Ausgabe
Einkauf: [object Object]
Product { name: 'Kaffee', price: 7.5, quantity: 1 }

Als Text ist das Objekt [object Object]. console.log auf dem Objekt selbst zeigt seine Felder, aber das ist zum Prüfen, während du Code schreibst. Es ist kein Text, den du in einen Satz setzen kannst.

Die Klasse kann sagen, wie sie angezeigt werden soll. Die Methode heißt toString() und gibt Text zurück:

class Product {
// die Felder und der Konstruktor, wie vorher
total() {
return this.price * this.quantity;
}
toString() {
return `${this.name} x${this.quantity}: ${this.total()} €`;
}
}
const coffee = new Product("Kaffee", 7.50, 1);
const bread = new Product("Brot", 1.20, 2);
console.log(String(coffee));
console.log(`Im Warenkorb: ${bread}`);
Ausgabe
Kaffee x1: 7.5 €
Im Warenkorb: Brot x2: 2.4 €

Du rufst sie nicht selbst auf. String(coffee), das Template-Literal `Im Warenkorb: ${bread}` und "Im Warenkorb: " + bread rufen sie für dich auf, wenn das Objekt zu Text werden muss. Nur console.log(coffee) ruft sie nicht auf: Es zeigt weiterhin die Felder.

Der Name muss genau toString sein, mit kleinem t und großem S. Woher das Objekt ein toString hat, noch bevor du eines schreibst, kommt im Modul „Vererbung und Polymorphie“.

Probier es aus

Ein Buch in einem Satz

Was gibt das Programm aus?

class Book {
title;
author;
constructor(title, author) {
this.title = title;
this.author = author;
}
toString() {
return `${this.title} von ${this.author}`;
}
}
const book = new Book("Der Zauberberg", "Thomas Mann");
console.log("Ich lese: " + book);
Antwort

Übung

Objekte, die etwas tun

Löse die Aufgaben in deinem Editor. Nimm die Klassen aus den früheren Lektionen und gib ihnen Methoden.

  1. Person: eine Methode introduce(), die Name und Alter ausgibt.
  2. SimpleCar: eine Methode accelerate(), die die Geschwindigkeit um 10 erhöht. Jetzt fasst der Code unter der Klasse die Geschwindigkeit nicht mehr direkt an.
  3. DanceMove: eine Methode perform(), die den Schritt „ausführt“.
  4. Book: eine Methode read(), die „Ich lese gerade [Titel] von [Autor]“ ausgibt.

Erzeuge von jeder Klasse ein Objekt und ruf seine Methoden auf:

Ausgabe
Hallo, ich bin Maria und bin 34 Jahre alt.
Geschwindigkeit nach dem Beschleunigen: 10
Ich tanze moonwalk für 5 Sekunden
Ich lese gerade Der Prozess von Franz Kafka

Übung

Ein Auto mit Tank

Eine Klasse Car mit Marke, Geschwindigkeit, Kraftstoff (in Litern) und Kilometerstand. Der Konstruktor bekommt Marke und Kraftstoff. Geschwindigkeit und Kilometerstand beginnen bei 0.

  • accelerate() erhöht die Geschwindigkeit um 10.
  • refuel(liters) tankt nach, aber in den Tank passen höchstens 50 Liter.
  • drive(distance) verbraucht 6 Liter auf 100 km und addiert die Strecke zum Kilometerstand. Reicht der Kraftstoff nicht, gibt die Methode eine Meldung aus, und das Auto fährt nicht.
  • toString() gibt Marke, Kilometerstand und Kraftstoff zurück.
Das Programm
const car = new Car("Toyota", 20);
car.accelerate();
car.accelerate();
console.log(`Geschwindigkeit: ${car.speed}`);
car.drive(100);
console.log(String(car));
car.drive(300);
car.refuel(40);
console.log(String(car));
car.drive(300);
console.log(String(car));
Ausgabe
Geschwindigkeit: 20
Toyota: 100 km, 14 l
Nicht genug Kraftstoff für 300 km
Toyota: 100 km, 50 l
Toyota: 400 km, 32 l
Tipp: distance * 6 / 100. In JavaScript gibt / immer eine Dezimalzahl, also bekommst du für 30 km 1,8 Liter.

Weitere Aufgaben

  • Rabatt. Gib Product eine Methode applyDiscount(percent), die den Preis des Produkts senkt. Vergleich sie mit der Funktion aus dem Modul „Funktionen“, die einen neuen Preis zurückgegeben hat.
  • Ein Konto mit Verlauf. Gib Account einen Zähler für Vorgänge: Jede Einzahlung und jede erfolgreiche Abhebung erhöht ihn um 1. Eine Methode toString() gibt Inhaber, Kontostand und Anzahl der Vorgänge zurück.

Test

Teste dich

1. Was macht maria.deposit(30)?
2. Was sieht eine Methode, das eine Funktion außerhalb der Klasse nicht sieht?
3. Warum bricht Account.withdraw(70) mit einem TypeError ab?
4. Wann ruft JavaScript toString() von selbst auf?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·