Klassen und Fehler in JavaScript
Klassen in JavaScript
Zuallererst: Klassen sind in JavaScript "nur" Syntactic Sugar, aufgebaut auf dem Konzept der Objekte.
Syntactic Sugar bezieht sich hierbei in Programmiersprachen darauf, dass komplexe Sachverhalte durch neue Paradigmen/Syntax vereinfacht werden.
Klassen in JavaScript sind aber "nicht so mächtig" wie andere Klassenbasierte Sprachen. Aber fangen wir einmal leicht an und definieren eine Klasse:
class MyClass { // Hier kommt alles zur Klasse rein } // Wir initialisieren eine // neue Instanz dieser Klasse mit "new" const instanz = new MyClass();
Felder / Properties einer Klasse können wir einfach in den Klassen-Body schreiben
class MyClass { propA = "foo"; propB = 42; } const instanz = new MyClass(); // "foo", 42 console.log(instanz.propA, instanz.propB);
Wenn wir Felder beim initialisieren belegen wollen indem wir Parameter übergeben, nutzen wir die constructor
Methode der Klasse
class MyClass { propA = undefined; constructor (paramA) { this.propA = paramA; } } const instanz = new MyClass('bar'); // "bar" console.log(instanz.propA);
Und wir können Klassen-Spezifische Funktionen definieren (und später auch aufrufen)
class MyClass { propA = undefined; constructor (paramA) { this.propA = paramA; } setPropA (param) { this.propA = param; } getPropA () { return this.propA; } }
Mit dem keyword static
können wir Statische Properties definieren.
Statische Properties hängen der Klasse direkt an und können ohne Instanz abgefragt / aufgerufen werden.
class MyClass { static property = "foo"; } console.log(MyClass.property);
Es können auch Methoden statisch deklariert werden. Dann muss man keine Instanz erstellen um auf diese Funktionen zuzugreifen.
Nützlich bei z.B. Helper-Utilities.
Klassen und Sub-Klassen
Es ist uns möglich Spezialisierte Klassen von Grundklassen zu erstellen.
class Animal { animalSound = undefined; constructor (sound) { this.animalSound = sound; } walk() { console.log(`I am walking... ${this.animalSound}!`); } speak() { console.log(this.animalSound); } }
class Dog extends Animal { breed = undefined; constructor (breed) { super('Woof'); this.breed = breed; } waggleTail () { if (this.breed === 'aussie') { throw new Error('I dont have a tail to wag!'); } console.log('Wagging Tail!'); } }
class Cat extends Animal { constructor() { super('Meow'); } knockOfTable(thing) { console.log(`${thing} should not be on the table ...`); } }
Errors
Natürlich gibt es auch Situationen in JavaScript die zu Fehlerzuständen führen können.
Wie in vielen anderen Sprachen gibt es auch in JS das Konzept diese Fehlerzustände in Form von Errors
abzubilden, die wiederum später "gefangen" werden können.
Erstellen wir zuerst einen Fehler. Hierzu gibt es die globale Klasse Error, die wir mit new
instanziieren können:
const myError = new Error("Da ist was schief gelaufen");
Bei der Ausführung geschieht aber erstmal nichts besonderes. Keine Fehlermeldung in der Konsole und weiterer Code würde einfach ausgeführt werden.
Um einen Fehler / Error zu werfen, müssen wir dies mit dem keyword throw
machen:
const myError = new Error("Da ist was schief gelaufen"); throw myError;
Nun sollte in der Konsole auch eine entsprechende Fehlermeldung auftauchen, mit der Nachricht die wir mitgegeben haben.
Fehler abfangen
Sobald ein Fehler durch throw
geworfen wurde, wird die Abarbeitung des Codes in der aktuellen Funktion unterbrochen und der Fehler an die Aufrufende Funktion geschickt.
Solange der Fehler nicht abgefangen wird, wird der Fehler in Funktion für Funktion nach oben geliefert bis zum (Call) Stack-Anfang
Um Fehler abzufangen, können wir die fragliche Funktion in ein try-catch
wrappen.
const failingFunction = function () { throw new Error("Da lief was schief"); } try { failingFunction(); console.log('Alles Fertig'); } catch { console.warn('Etwas lief schief, aber wir haben das abgefangen'); }
Wir können auch auf die eigentliche Fehlermeldung zugreifen, indem wir nach dem catch ähnlich zu Parametern, einen Wert erwarten.
const failingFunction = function () { throw new Error("Da lief was schief"); } try { failingFunction(); console.log('Alles Fertig'); } catch (err) { console.warn('Etwas lief schief, aber wir haben das abgefangen'); // Der Angegebene text befindet // sich in der prop "message" console.log(err.message); }
Wir können neben dem Error-Text noch eine weitere Information angeben: Was der Grund des Fehlers gewesen ist
const failingFunction = function () { throw new Error("Da lief was schief", { cause: "User Input wrong" }); } try { failingFunction(); console.log('Alles Fertig'); } catch (err) { console.warn('Etwas lief schief, aber wir haben das abgefangen'); console.log(err.message); console.log(err.cause); }
Wir viel / Wie sehr sollte man nun Error nutzen?
Aus eigener Erfahrung, lohnt es sich auf Fehler-Zustände direkt zu reagieren, anstatt den Fehler zu ignorieren / woanders abzuhandeln.
Wichtigster Punkt ist aber: Wenn ein Fehler aufkommt, von dem der User wissen sollte, sollte man dem User auch einen Fehler anzeigen.
Es gibt verschiedene Möglichkeiten dies zu tun. Welche Ideen habt ihr / Was habt ihr gesehen?