JavaScript/Tutorials/OOP/Objektabfrage

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
Hinweis:
Man hat in JavaScript mit der (scheinbar) chaotischen losen Typisierung immer wieder mal das Problem, dass man bei Vergleichen wissen muss, warum so manches if-Statement plötzlich true oder false ergibt. Gerade Anfänger oder Fortgeschrittene wundern sich manchmal an manchen Stellen und können mit diesem Artikel vertiefen, was sie bisher eher "nach Gefühl" gemacht haben.

Zeitgemäße JavaScript sollen robust und browserübergreifend funktionieren, mit anderen Scripten problemlos zusammenarbeiten und unter Umständen von fremden Entwicklern angesteuert werden. Bis vor einiger Zeit wurden zu diesem Zweck zuhauf zweifelhafte »Browserweichen« eingesetzt, die z. B. mithilfe von des navigator-Objektes versuchten, den Browser anhand seines Namens zu identifizieren. Diese Erkennung wurde dann verwendet, um indirekt auf die Fähigkeiten des Browsers zu schließen.

Dieser Weg ist in der heutigen Weblandschaft, in der die Browser in ihren verschiedenen Versionen unzählige Techniken unterschiedlich umsetzen, nicht mehr gangbar. Der Browsermarkt und die Entwicklung neuer, in JavaScript nutzbarer Techniken ist zu stark in Bewegung, als dass eine solche »Browserweiche« zuverlässig und zukunftsfähig sein könnte. An deren Stelle sind »Fähigkeitenweichen« getreten. Diese fragen nicht allgemein den Namen des Browsers ab und versuchen Rückschlüsse auf die Unterstützung gewisser Techniken, sondern prüfen konkret die Existenz derjenigen JavaScript-Objekte, die im Laufe des Scriptes verwendet werden. Entscheidend ist dann, ob die nötigen Objekte existieren und korrekt funktionieren, etwa dass Eigenschaften einen erwarteten Wert oder Methoden das spezifizierte Ergebnis haben.

Unter anderem aus diesen Gründen spielt die Abfrage von Objekten heutzutage eine zentrale Rolle in JavaScript. Leider sieht eine Objektabfrage im Einzelfall sehr unterschiedlich aus. Welche Abfrage in welchem Fall die effektivste und zuverlässigste ist, erschließt sich nicht ohne Weiteres. Dieser Artikel soll die Grundlagen einer Objektabfrage erklären und anschließend die verschiedenen verbreiteten Objektabfragen diskutieren. Ziel ist es, die Funktionsweise und die geeigneten Anwendungen verschiedener Abfrage-Techniken zu vermitteln.


Bestandteile einer Objektabfrage

Objektabfragen haben drei Ebenen:

  • Abfrage der Existenz: Existiert ein Objekt überhaupt? (Hat es überhaupt irgendeinen Wert oder ist es »nicht definiert«?)
  • Abfrage des Types: Hat ein Objekt den gewünschten Typ?
  • Wertabfragen: Abfrage des Wertes: Hat ein Objekt den gewünschten Wert?

Diese Abfragen müssen manchmal gestaffelt sein: Denn wenn ein Objekt gar nicht existiert, ist unter Umständen Vorsicht geboten bei der Abfrage des Types. Und die Abfrage des Wertes schließt ein, dass ein bestimmter Typ vorausgesetzt wird. Am Anfang steht daher die Überlegung, welche dieser Ebenen überhaupt geprüft werden soll.

Boolean-Abfragen

Unter Abfragen verstehen wir hier vor allem bedingte Verzweigungen mit if (...) { ... } else { ... }. Im engeren Sinne werden wir uns mit der Bedingung beschäftigen, die bei der if-Anweisung zwischen den runden Klammern notiert wird. Dieselben Bedingungen finden aber auch bei anderen bedingten Anweisungen, nämlich dem sogenannten konditionalen Operator und bei switch-Fallunterscheidungen Verwendung.

Diese Bedingung ist ein beliebiger JavaScript-Ausdruck (»Expression«), welcher einen Boolean-Wert ergeben muss – das heißt true oder false. Der JavaScript-Interpreter wandelt das Ergebnis des Ausdrucks zwischen den Klammern automatisch in den Typ Boolean um, sofern es einen anderen Typ hat. Diese Umwandlung gehorcht festen Regeln, die wir nun kennenlernen werden.

Was ergibt also in Boolean umgewandelt true? Anders herum gefragt: Welche Werte ergeben in Boolean umgewandelt false?

  • Der Boolean-Wert false ergibt logischerweise false.
  • Die Werte null und undefined ergeben false.
  • Die Zahlen (Typ Number) 0 und NaN ergeben false.
  • Ein leerer String ("") ergibt false.

Alle anderen Werte ergeben true.

Das bedeutet: Vordefinierte Objekte wie window und window.document, Funktionsobjekte, DOM-Knoten-Objekte, darunter Elementobjekte, sowie Array-, Date- und RegExp-Objekte ergeben allesamt true. Kurz gesagt ergeben nicht-leere Strings, Zahlen ungleich 0 bzw. NaN und »richtige« Objekte (Objects, dazu später mehr) true.

Diese Regeln sind normativ im ECMAScript-Standard spezifiziert, speziell in der internen Funktion ToBoolean, welche u. a. bei der Verarbeitung eines if-Statements aufgerufen wird.


if (objekt)

Prüft, ob eine globale oder lokale Variable nach Boolean umgewandelt true ergibt. Wenn weder eine lokale noch eine globale Variable dieses Namens existiert, bricht das Script hier mit einem Ausnahmefehler (einer exception) ab: ReferenceError: objekt not defined.

Eignet sich zur Abfrage, ob einer deklarierten lokalen Variable ein Wert zugewiesen wurde, der bei der Umwandlung in Boolean true ergibt. Deklariert bedeutet, dass var objekt; notiert wurde oder die Variable in der Parameterliste der Funktion aufgeführt ist, ohne dass ein Wert für sie übergeben wurde. objekt hat dann den speziellen Wert undefined, was in Boolean umgewandelt false ergibt.

Beachten Sie: Eignet sich nicht ohne Einschränkungen zum Überprüfen, ob einer deklarierten Variable überhaupt ein Wert zugewiesen wurde. Denn wie oben aufgelistet ergeben ein leerer String (""), der Boolean-Wert false sowie null ebenfalls false.


if (objekt == true)

Dies ist eine lange Schreibweise von if (objekt). Sie hat jedoch nicht denselben Effekt, sondern funktioniert intern ganz anders.

Wenn Sie den Vergleichsoperator verwenden, so wird der sogenannte Abstract Equality Comparison Algorithm (abstrakter Algorithmus zur Ermittlung der Gleichheit) angewendet. Dieser wandelt object nicht einfach in Boolean um. Wie er genau abläuft, hängt von den Typen der beiden Operanden ab (hier objekt und true).

Wenn beide Typen sich unterscheiden, so wird zunächst der Boolean-Operand mithilfe von ToNumber in eine Zahl (Number) umgewandelt. true ergibt dabei 1, false ergibt 0. Der Vergleich objekt == true wird also zu objekt == 1 umgeschrieben. Danach wird objekt ebenfalls in eine Zahl umgewandelt, um die beiden Operanden vergleichen zu können. Falls objekt ein »echtes« Objekt (Object) ist, so wird das Objekt in einen einfachen Wert (Primitive) umgewandelt, indem dessen Methoden valueOf oder toString aufgerufen werden. (Zur Unterscheidung zwischen Objects und Primitives siehe unten.)

Kurz gesagt, dabei kann etwas ganz anderes herauskommen als beim einfachen if (objekt). Ein paar Beispiele:

Eingabe if (objekt) alert('ja');
else alert('nein');
if (objekt == true) alert('ja');
else alert('nein');
0 nein nein
1 ja ja
123 ja nein
"" nein nein
" " ja nein
"ein String" ja nein
"0" ja nein
"1" ja ja
window ja nein
window.setTimeout ja nein
{ valueOf : function () { return 0; } }
(Ein Objekt mit einer valueOf-Methode)
ja nein
{ toString : function () { return "ein Object"; } }
(Ein Objekt mit einer toString-Methode)
ja nein

Ein ausdrücklicher Vergleich mit true bzw. false führt nur selten zu dem gewünschten Resultat, da intern mit Zahlen als Vergleichswerten gearbeitet wird. Sofern dieses Verhalten nicht ausdrücklich gewünscht ist, sollten Sie if (objekt) und if (!objekt) anstelle von if (objekt == true) und if (objekt == false) verwenden. Das gilt insbesondere für Fähigkeitenabfragen.

if (objekt == undefined)

Genauere Überprüfung, ob eine globale oder lokale Variable deklariert wurde, ihr aber kein Wert zugewiesen wurde. Wenn ein Funktionsparameter in der Parameterliste aufgeführt ist, aber kein Wert übergeben wurde, existiert eine entsprechende lokale Variable ohne Wert.

Beispiel
function funktionMitParameter (parameter) {
   if (parameter == undefined) {
      alert('Es wurde kein Parameter übergeben (oder ausdrücklich undefined)');
   }
}
// Aufruf ohne Parameter
funktionMitParameter();

Hat die Variable den Wert null, so ergibt der Vergleich mit undefined ebenfalls true. Um diese Mehrdeutigkeit zu vermeiden, können Sie if (objekt === undefined) notieren. Der Identitätsoperator === überprüft sowohl die Gleichheit des Typs (hier Undefined) als auch die Gleichheit des Wertes (hier undefined).

Wenn keine Variable dieses Namens existiert, bricht das Script an dieser Stelle mit einem Ausnahmefehler (einer exception) ab: ReferenceError: objekt not defined.


if (objekt == wert)

Beispielsweise if (objekt == "string") oder if (objekt == 1234) usw. Überprüfung der Wertgleichheit von globalen oder lokalen Variablen.

Damit die Vergleiche die erwarteten Resultate bringen, sollten beide Operanden vom gleichen Typ sein. Andernfalls erfolgt eine automatische Umwandlung auf Basis des beschriebenen Gleichheits-Algorithmus, der beide Operanden in eine Zahl (Number) umzuwandeln versucht.

Wenn keine Variable dieses Namens existiert, bricht das Script an dieser Stelle mit einem Ausnahmefehler (einer Exception) ab: ReferenceError: objekt not defined.


if (objekt.eigenschaft) und if (objekt["eigenschaft"])

Prüft, ob ein Objekt eine Eigenschaft (Unterobjekt) besitzt, die in Boolean umgewandelt true ergibt.

Wenn das Objekt keine Eigenschaft dieses Namens besitzt, bricht das Script an dieser Stelle nicht mit einem Ausnahmefehler ab. Der Ausdruck objekt.eigenschaft ergibt dann einfach undefined, welches in Boolean umgewandelt false ergibt. Dadurch würde der if-Anweisungsblock nicht ausgeführt. Sie können daher auch if (objekt.eigenschaft == wert) verwenden, um auf einen bestimmten Wert zu prüfen, ohne dass das Script abbricht, wenn die Eigenschaft nicht existiert.

Dies ist die beste Methode für »Fähigkeiten-Weichen«, die abfragen, ob vordefinierte Objekte (bzw. Eigenschaften oder Methoden) im jeweiligen Browser zur Verfügung stehen. Besonders für die Existenzabfrage von Methoden eignet sich diese Schreibweise.

Beispiel
if (document.getElementById) {
	let elem = document.getElementById("a");
	if (elem.scrollIntoView) {
		elem.scrollIntoView();
	}
}

Existieren die Methoden getElementById bzw. scrollIntoView, werden sie verwendet, anderweitig wird der entsprechende Code übersprungen.

Interessant ist ferner, dass sich auf diese Weise auch globale Variablen überprüfen lassen. Denn globale Variablen sind in JavaScript Eigenschaften des globale Objektes window. Also kann man einfach if (window.globaleVariable) oder if (window["globaleVariable"]) notieren. Der Vorteil gegenüber if (globaleVariable) ist, dass das Script nicht mit einem Ausnahmefehler abbricht, wenn selbige Variable nicht existiert.

Typabfragen

if (typeof objekt == "typ") und if (typeof objekt.eigenschaft == "typ")

Mit dem typeof-Operator lässt sich abfragen, ob eine Variable bzw. eine Objekteigenschaft einen bestimmten Typ hat. typeof gibt einen String zurück, je nach Typ des Operanden gemäß der folgenden Tabelle:

Typ des Operanden typeof-Rückgabe
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
String "string"
Funktionsobjekte "function"
sonstige Objekte (»Objects«, siehe unten) "object"

typeof in JavaScript verhält sich ganz anders als entsprechende Operatoren bzw. Funktionen in anderen Programmiersprachen. Das hat damit zu tun, wie JavaScript intern organisiert ist. Zum Verständnis von typeof ist ein kleiner Exkurs nötig:

Objects und Primitives

JavaScript (ECMAScript) behandelt zwar alles als Objekt, macht eine Unterscheidung zwischen sogenannten Primitives (einfachen Werten) und Objects (»richtigen«, vollwertigen Objekten). Diese Doppelung betrifft Boolean-, Number- und String-Werte, diese können als Primitive oder als Object notiert werden. Üblicherweise arbeitet man mit Primitives: let string = "Hallo Welt" sowie die üblichen String-Operationen erzeugen String-Primitives, während let string = new String("Hallo Welt"); ein String-Object erzeugt. Dieser Unterschied macht sich vor allem an zwei Stellen bemerkbar:

  • Primitives werden als Kopie an Funktionen übergeben, während Objects als Referenz (genauer gesagt als Referenzkopie) übergeben werden.
  • Der Vergleichsoperator == ergibt beim Vergleich zweier Objects nur dann true, wenn es sich um ein und dasselbe Object handelt. Das heißt, er verhält sich in dem Fall wie der Identitätsoperator ===. Daher ergibt new String("Hallo Welt") == new String("Hallo Welt") kurioserweise false. Bei Primitives hingegen gibt es eine Gleichheit unabhängig von der Identität: "Hallo Welt" == "Hallo Welt" ergibt selbstverständlich true.

Was hat das nun mit typeof zu tun? typeof unterscheidet im Grunde nur zwischen undefinierten Werten (Undefined), den drei Primitives (Boolean, Number, String) und Objects (Funktionen vs. alle anderen Objects). Was null, kein Primitive und kein Funktionsobjekt ist, klassifiziert typeof zusammenfassend als "object". Dadurch gibt typeof sehr häufig "object" zurück, was Verwirrung stiftet. Zum Beispiel werden Array-, Date- oder RegExp-Objekte als "object" klassifiziert – diese sind aus Sicht von typeof kein eigenen Typen. Aber auch der Wert null wird als "object" klassifiziert, obwohl es sich strenggenommen um ein Primitive handelt – dies kann einige Verwirrungen stiften.

Browserprobleme und Konsequenzen

Dummerweise setzen nicht alle Browser diese Vorgaben der obigen Tabelle konsequent um, sodass typeof in verschiedenen Browsern z. B. bei gleichen vordefinierten Objekten unterschiedliche Resultate erzeugt. In manchen Browsern identifiziert typeof ein vordefiniertes Funktionsobjekt fälschlicherweise als "object" anstatt als "function".

Diese Einschränkungen und Fallstricke führen dazu, dass eine Abfrage typeof nur in bestimmten Fällen das Mittel der Wahl ist. Verwenden Sie typeof möglichst nur bei einfachen Werten (Boolean-, Number- und String-Primitives) und nur bei selbst definierten Funktionen. Achten Sie auf mögliche Browserunterschiede und die Besonderheiten bei der Klassifizierung.


Anwendungsgebiete

Nichtsdestoweniger ist typeof die zweitwichtigste Abfragetechnik in der browserübergreifenden Programmierung neben if (objekt.unterobjekt). Der Vorteil ist, dass nur der Typ überprüft wird, nicht der Wert selbst in Boolean umgewandelt und auf Gleichheit mit true getestet wird, wie es z. B. bei if (objekt.unterobjekt) der Fall ist. Wenn bloß die Existenz einer Variable geprüft werden soll, es sich aber beispielsweise durchaus um einen leeren String, die Zahl 0 oder den Boolean-Wert false handeln darf, eignet sich typeof .

Abfragen mit typeof sind wie gesagt weniger streng als if (objekt.unterobjekt), da der Wert selbst keiner Boolean-Prüfung unterzogen wird. Dennoch sind die beiden Möglichkeiten in vielen Fällen austauschbar. Oft ist es eine Geschmackfrage, welche Methode verwendet wird. Meine Empfehlung ist, häufiger if (objekt.unterobjekt) zu verwenden und typeof speziell dann zu verwenden, wenn der Inhalt egal ist, solange der Typ stimmt.

Wenn keine Variable bzw. Eigenschaft den angegebenen Namens existiert, bricht das Script beim typeof -Operator nicht mit einem Ausnahmefehler ab, sondern typeof liefert den String "undefined" zurück.

Robuste Scripte durch passende Typabfragen und Typumwandlungen

Strenge Typabfragen können verwirrend sein, da JavaScript flexibel mit Typen umgeht, um die Programmierung zu vereinfachen. Je nach Kontext werden Werte bei der Code-Ausführung automatisch in andere Typen konvertiert, z. B. damit Operanden und Funktionen mit den erwarteten Typen arbeiten können. Dies ist vielmals erwünscht und findet breite Verwendung, ohne dass JavaScript-Programmierer sich dessen notwendigerweise bewusst sind. Es ist nicht immer problematisch, wenn eine Variable z. B. anstelle des Wertes 250 vom Typ Number den Wert "250" vom Typ String enthält. Es kann aber ein großes Problem werden. Etwa variable.toFixed() funktioniert nur bei Number-Werten und der Operator + hat eine ganz andere Bedeutung, wenn ein Operand ein String ist.

Wenn Sie also typeof benutzen, um einen speziellen Typ abzufragen, sollten Sie sich mit den Möglichkeiten der automatischen und manuellen Typen-Konvertierung vertraut machen. Benutzen Sie etwa parseInt oder parseFloat zur Umwandlung von Strings in Zahlen und toString zur expliziten Umwandlung von Zahlen in Strings. So können Sie robuste, tolerante Programme schreiben:

Beispiel
function zahlenverarbeitung (parameter) {
   let zahl;
   if (typeof parameter == "string") {
      // Es wurde ein String übergeben, wandle in Zahl um
      zahl = parseFloat(parameter);
      if (isNaN(zahl) {
         // Umwandlung in String ergab keinen brauchbaren Wert
         return false;
      }
   } else if (typeof parameter == "number") {
      // Es wurde eine Zahl übergeben, wir können direkt damit arbeiten
      zahl = parameter;
   } else {
      // Es wurde kein brauchbarer Wert übergeben
      return false;
   }
   // Arbeite mit zahl weiter
}

Das obige Beispiel ist bewusst sehr ausführlich, um das Reagieren auf verschiedene Parameter-Typen zu demonstrieren. Konkret diese Logik ließe sich auch kompakter ohne typeof umsetzen, indem der Parameter direkt parseFloat() gegeben wird und anschließend nur noch geprüft wird, ob es sich um eine gültige Zahl handelt:

Beispiel
function zahlenverarbeitung (parameter) {
   let zahl = parseFloat(parameter);
   if (isNaN(zahl) {
      // Umwandlung in String ergab keinen brauchbaren Wert
      return false;
   }
   // Arbeite mit zahl weiter
}

Wertabfragen

if (typeof objekt != "undefined") und if (typeof objekt.eigenschaft != "undefined")

Prüft, ob eine lokale oder globale Variable bzw. eine Objekteigenschaft dieses Namens existiert und zudem einen Wert besitzt (der nicht vom Typ Undefined ist).

Aufgrund der beschriebenen Eigenheiten und Browser-Probleme wird typeof häufig in diesem negativen Sinne gebraucht. Anstatt abzufragen, ob ein Objekt einen bestimmten Typ hat, wird bloß abgefragt, ob es existiert und irgendeinen anderen Typ als Undefined besitzt. Damit kann beispielsweise die bloße Existenz vordefinierter Objekte in Erfahrung gebracht werden oder geprüft werden, ob ein Funktionsparameter gesetzt wurde, unabhängig davon, welchen Typ und welchen Wert dieser hat.

Der negative Vergleich mit "undefined" ist zwar ungenauer als die Prüfung auf einen oder mehrere bestimmte Typen, erfüllt aber oft trotzdem den gewünschten Zweck. Diese Methode findet an ähnlichen Stellen Verwendung wie if (objekt.unterobjekt).

if (objekt == null) und if (objekt.unterobjekt == null)

Der Vergleich mit null ergibt true, wenn das Objekt den Wert null oder undefined ist (siehe auch den Abschnitt zu undefined).

Wenn keine Variable dieses Namens existiert, bricht das Script an dieser Stelle mit einem Ausnahmefehler (einer Exception) ab: ReferenceError: objekt not defined.

Zur Objekterkennung eignet sich die Prüfung auf null weniger. Sie können jedoch in ihren eigenen Programmen den Wert null verwenden, um »kein Wert« von Werten wie "", 0 und false abzugrenzen. Sie können z.B. eine eigene Funktion null zurückgeben lassen, um zu zeigen, dass die Funktion korrekt ausgeführt wurde, aber das Ergebnis »kein Wert« ist (auch kein leerer String oder 0). Ähnlich handhaben es einige Methoden des W3C-DOM. In diesen Fällen ist der Vergleich mit null angebracht.


if ("eigenschaft" in objekt)

Diese relativ unbekannte Abfrage prüft, ob das Objekt eine Eigenschaft mit dem angegebenen Namen besitzt. Weder Typ noch Wert werden dabei überprüft. Der Ausdruck ergibt direkt true oder false. Es entspricht if (typeof objekt.eigenschaft != "undefined") bis auf den Fall, in dem die Eigenschaft zwar gesetzt ist, aber den Wert undefined hat.

Der Eigenschaftsname kann hier direkt als String angegeben werden oder als String-Variable, die den Namen der zu prüfenden Eigenschaft enthält. In letzterem Fall notiert man if (stringVariable in objekt).

Ein Beispiel ist die Abfrage, ob der Browser einen gewissen Event-Typ unterstützt . Unterstützt der Browser beispielsweise den Event hashchange, so existiert die Eigenschaft onhashchange. Wenn kein Event-Handler registriert ist, ist diese Eigenschaft jedoch initial leer, üblicherweise null.

Beispiel
if ('onhashchange' in window) {
   // Event wird unterstützt, registriere einen Event-Handler
   window.onhashchange = function () { ... };
} else {
   // Event wird nicht unterstützt, Alternativtechniken greifen
   // Firefox braucht eine Extra-Abfrage
}

Die Praxis ist etwas komplizierter, da diese Abfrage im Firefox ein falsches Resultat ergibt. Wie der verlinkte Artikel beschreibt, existiert jedoch eine Alternative für Firefox.

Der in-Operator ist vor allem aus for-in-Schleifen bekannt. Dort hat er allerdings eine ganz andere Bedeutung und führt dazu, dass der Variablen auf der linken Seite nacheinander die Eigenschaftsnamen zugewiesen werden und für Eigenschaft der Schleifenkörper ausgeführt wird.

Wenn keine Eigenschaft mit dem angegebenen Namen existiert, bricht das Script an der Stelle der Verwendung des in-Operators nicht mit einem Ausnahmefehler ab, sondern liefert einfach den Boolean-Wert false zurück.


try { /* direkt objekt benutzen */ } catch (e) {}

Das try-catch-Statement dient eigentlich dazu, Ausnahmefehler (exceptions) abzufangen und sie im catch-Zweig selbst zu behandeln. Damit lässt sich punktuell auf einen aufgetretenen Fehler reagieren, der sonst zum Abbruch des Scriptes führen würde. Dieses Konzept ist eigentlich sehr brauchbar. Allerdings gibt es zwei Probleme, sowohl grundlegender als auch praktischer Art.

Zum ersten wird try-catch in den wenigsten Fällen sinnvoll verwendet. Oft wird der catch-Zweig leer gelassen, bloß um eventuelle Exceptions und damit verbundene Fehlermeldungen im Browser zu unterdrücken. Eine Fehlerbehandlung findet also nicht statt. try-catch wird in dieser Weise inflationär gebraucht, anstatt zielgenaue Objektabfragen bzw. tatsächliche Fehlerbehandlung einzusetzen.

Zum zweiten ist es mit try-catch nicht möglich, spezifisch auf einen Fehler zu reagieren, wenn große Programmteile in try-Blöcke untergebracht werden. Das Fehlerobjekt, auf das man im catch-Block Zugriff hat, enthält wenig brauchbare Informationen. Die Fehlermeldung kann höchstens abgefangen werden, um sie beispielsweise mit XMLHttpRequest an den Server zurückzusenden. Dort könnten alle Fehlermeldungen gespeichert werden, um Scripte zu verbessern, damit sie in Zukunft keine Exceptions mehr produzieren.

Der Einsatz von try-catch zur Fehlerunterdrückung während der Entwicklung führt dazu, dass Scriptfehler nicht rechtzeitig erkannt werden. Robuster, fehlertoleranter JavaScript-Code sollte im Produktiveinsatz auch in Sonderfällen keine unerwarteten Exceptions auslösen. Daher erwähnt dieser Artikel jeweils, welche Abfragetechniken Exceptions auslösen und welche nicht, auch wenn die angesprochene Variable bzw. Eigenschaft nicht existiert. Mit diesen »sicheren« Objektabfragen können Sie Exceptions von vornherein vermeiden.

Es gibt noch weitere Argumente gegen einen unbedachten Einsatz von try-catch: Beispielsweise ist die Ausführung viel langsamer als die hier beschriebenen zielgenauen Abfragen. Zusammenfassend: Verwenden Sie try-catch nur im Notfall, wenn andere Objektabfragen nicht möglich sind oder nicht greifen.

Es gibt nur wenige Fälle, in denen try-catch nützlich oder gar nötig ist. Etwa wenn bekannt und spezifiziert ist, dass eine Anweisung bei der regulären Verwendung eine Exception auslösen kann. Doch nur wenige JavaScript- und DOM-Operationen erzeugen bei korrekter Anwendung und sinnvollen Eingabedaten Exceptions.

try-catch soll keinesfalls verdammt werden. Sein Einsatz ist lediglich zum Zwecke der Fehlerunterdrückung und Fallunterscheidung nicht sinnvoll, weil genauere und bessere Alternativen für robuste Scripte existieren. Es spricht nichts dagegen, try-catch bei einer erwarteten Exception zu verwenden, um im catch-Zweig Alternativen anzuwenden und die Aufgabe auf eine andere Weise zu lösen. Es spricht auch nichts gegen den kontrollierten Einsatz von try-catch und throw, um die bestimmte Ausnahme auf einer höheren Ebene zu behandeln.

Weblinks

englischspachig: