Warum `catch ()` einen SyntaxError in JavaScript auslöst
Erfahren Sie, warum eine leere Catch-Parameterliste die JavaScript-Parsing-Funktion völlig stört, und sehen Sie sich die beiden grammatikalisch korrekten Möglichkeiten an, einen parameterlosen Catch-Block zu schreiben.
Auf den ersten Blick scheint der Auszug „Error“ auszugeben. In Wirklichkeit tritt ein SyntaxError auf, weil die Schreibweise catch () ohne Inhalt in den Klammern niemals gültiger JavaScript war.
Stellen Sie sich ein zweites Vorstellungsgespräch im Frontend-Bereich vor. Was wie eine Einstiegsfrage wirkte, entpuppte sich als schwieriger. Der Interviewer bat um ein try-catch-Strukturen, das einen Fehler auslöst und eine Nachricht im catch-Block protokolliert, fügte dann einen Hinweis hinzu: „Sie benötigen das Fehlerobjekt nicht.“
Falls man das Fehlerobjekt nicht benötigt, ist der natürliche Schritt, seine Deklaration wegzulassen. Jahre des Schreibens von Code wie function handler() {} bringen einen dazu, die Parameterliste einfach leer zu lassen:
try {
throw "Error";
} catch () {
console.log('Error')
}
Wenn man fragt, was hier ausgegeben wird, scheint die offensichtliche Antwort „Error“ zu sein: Der String wird ausgeworfen, der Catch-Block wird ausgeführt und console.log wird aufgerufen. Doch als der Interviewer den Code tatsächlich ausführte:
Uncaught SyntaxError: Unexpected token ')'
Es wird nichts ausgegeben – weder „Error“ noch irgendetwas anderes. Die Skript wird keinen einzigen Befehl ausführen. Genau da sagte der Interviewer den Satz, von dem dieser Artikel seinen Titel hat:
Ihre fünfjährige Erfahrung in JavaScript reicht nicht aus, um zu wissen, wie ein Try-Catch-Block funktioniert.
Es war nicht als Frage formuliert. Es handelte sich um eine Aussage – und zwar eine unangenehme, weil sie zufällig der Wahrheit entsprach. In fünf Jahren JavaScript-Entwicklung hatte dieser Entwickler noch nie catch () eingegeben. Der Parameter hatte stets einen Namen, selbst in Fällen, in denen er nie tatsächlich referenziert wurde. Der erste Versuch, ihn wegzulassen, zeigte eine Regel auf, die einfach nie gelernt worden war.
catch hat genau zwei zulässige Formen
Die formale Grammatik für die catch-Klausel (ECMA-262, Abschnitt 14.15, The try Statement) ist kompakt:
Catch :
catch ( CatchParameter ) Block
catch Block
CatchParameter :
BindingIdentifier
BindingPattern
Betrachten Sie sich die erste Regel genau. Wenn Klammern vorhanden sind, ist ein CatchParameter darin zwingend erforderlich. In der Grammatik wird dies nirgends als optional markiert. Es muss sich auf genau eine Bindung beziehen: einen einfachen Identifikator wie e oder ein Destructuring-Muster wie {message}. Ein leeres Klammerpaar erfüllt keine dieser Regeln.
Die zweite Regel, die mit ES2019 eingeführt wurde, entfernt die Klammern vollständig. Leere Klammern passen zu keiner Regel. Wenn der Parser daher catch ( liest, erwartet er als Nächstes ein gültiges Bindungstoken, findet stattdessen ) und bricht ab. Genau diese Fehlermeldung wird von V8 ausgelöst: Unexpected token ')'.
Dies wirft eine berechtigte Frage auf: Warum wird function f() {} problemlos kompiliert, während catch () {} das nie tut? Die Parameterliste einer Funktion folgt der FormalParameters-Syntax, die null Parameter, Standardwerte sowie eine Restsyntax zulässt. CatchParameter wurde absichtlich anders konzipiert – er repräsentiert genau eine erforderliche Bindung, ohne mit Kommas getrennte Liste, ohne Standardwerte und ohne Restelement. Catch kennt keinen Begriff einer leeren Parameterliste, weshalb der Denktrick „man füllt die Klammern einfach leer“ – der bei Funktionen funktioniert – hier nicht anwendbar ist.
Dieser Fehler tritt bereits vor dem Ausführen des Codes auf
In diesem Fehler steckte noch ein weiterer Irrtum: die Annahme, dass Fehler ausschließlich ein Laufzeitphänomen sind. Dieser spezielle Fehler tritt während des Parsens auf, noch bevor die Ausführung überhaupt beginnt. Der Interpreter durchsucht den gesamten Script-Text, findet keine Übereinstimmung mit der Grammatik und meldet einen SyntaxError, bevor auch nur eine einzige Zeile ausgeführt werden kann. Alles andere in dieser Datei wird dadurch mit beeinträchtigt.
Durch Hinzufügen einer weiteren Zeile wird das deutlich. Folgendes wurde in Chrome bestätigt:
console.log('before'); // NEVER runs
try { throw "Error"; } catch() { }
Uncaught SyntaxError: Unexpected token ')'
Die Zeile console.log('before') befindet sich oberhalb der fehlerhaften catch-Klausel und an sich ist damit nichts falsch, wird dennoch nie ausgegeben. Da das gesamte Script nicht kompiliert werden kann, wird auch nichts davon ausgeführt.
Dies führt zu einem Schluss, der auf den ersten Blick leicht übersehen werden kann: ein try-catch-Block innerhalb einer Datei kann keinen SyntaxError fangen, der aus derselben Datei stammt. Damit ein Catch-Block ausgeführt werden kann, müsste der umgebende Code bereits erfolgreich analysiert worden sein – genau das ist jedoch fehlgeschlagen. Die einzige Möglichkeit, diese Art von Fehler zu fangen, besteht darin, dies aus einer völlig separaten Kompiliereinheit heraus mithilfe von eval, new Function oder einem dynamischen import() zu tun.
Die beiden korrekten Schreibweisen
Sowohl die unten beschriebenen Ansätze wurden in Chrome überprüft und sind beide gültig.
Option 1: Den Parameter beibehalten, ihn aber nicht verwenden. Es ist völlig zulässig, einen Catch-Parameter zu deklarieren, auf den man nie zurückgreift – und das war in jeder Version von ECMAScript schon immer der Fall.
try {
throw "Error";
} catch (e) {
console.log('caught, e unused');
}
// logs: caught, e unused
Option 2: Die Klammern ganz entfernen. Das ist die optionalen Catch-Bindingsyntax von ES2019: keine Klammern, kein Parameter, einfach nur catch {.
try {
throw "Error";
} catch {
console.log('caught without binding');
}
// logs: caught without binding
Das zu behaltende mentale Modell: Die Abkürzung von catch (e) bedeutet Entfernen der Klammern, nicht das Löschen dessen, was sich darin befindet. Der Mittelweg zwischen diesen beiden gültigen Formen ist genau der Punkt, an dem der SyntaxError auftritt.
Ursprung der syntax ohne Klammern
Die optionale Catch-Bindingsyntax entstand ursprünglich als TC39-Vorschlag von Michael Ficarra. Im Januar 2018 erreichte sie Phase 4 und wurde Teil von ES2019. Die Unterstützung durch Browser und Laufzeiten folgte schnell: Chrome 66, Firefox 58, Safari 11.1 sowie Node.js 10 unterstützen sie alle, was bedeutet, dass sie in praktisch jedem heutigen Umfeld sicher verwendet werden kann.
Die Begründung für den Vorschlag entspricht genau dem Szenario, das den Bewerber in Verlegenheit brachte: Code, bei dem der gefangene Fehler tatsächlich nie benötigt wird. Man denke an die Überprüfung, ob eine Zeichenkette als gültiges JSON interpretiert werden kann, und falls nicht an den Rückgriff auf einen Standardwert, oder an Muster zur Erkennung von Funktionen, bei denen bereits das Erfassen des Fehlers alle notwendigen Informationen liefert. In solchen Fällen führt die Benennung des Fehlers als e lediglich zu einer Variablen, der Werte zugewiesen werden, aber sie niemals gelesen werden – und der Vorschlag selbst weist darauf hin, dass dieses Muster in der Regel auf einen Fehler an einer anderen Stelle im Code hindeutet.
Es lohnt sich, genau zu beschreiben, was der Vorschlag tatsächlich geändert hat: Er führte eine neue Grammatikstruktur für einen Catch-Block ein, der überhaupt keine Parameterliste enthält. Er legalisierte leere Klammern nicht – die Klammern werden nicht leer gelassen, sondern vollständig entfernt. Dadurch bleibt die Regel gewahrt, dass CatchParameter, sofern vorhanden, genau eine Bindung sein muss, und es wird catch { visuell mit finally { vereinheitlicht, einem Block, der ursprünglich nie Klammern hatte.
Warum selbst erfahrene Entwickler darauf hereinfallen
Es gibt drei verschiedene Gründe, warum dies Menschen in die Irre führt – und keiner davon liegt an mangelndem Aufwand oder Studium.
Ihre Intuition stammt hier von einem anderen, vertrauteren Muster – und sie führt Sie in die Irre. Jede Funktionssignatur, die Sie je geschrieben haben, unterstreicht die Vorstellung, dass eine ungenutzte Parameterliste auf leere Klammern reduziert werden kann: function () {} ist völlig normal. Da eine Catch-Klausel optisch einer Funktionseinleitung ähnelt, erscheint es natürlich, denselben Abkürzungsweg anzuwenden. Doch eine Catch-Klausel nimmt keine Parameterliste entgegen – sie nimmt nur eine einzige Bindung entgegen – und die Grammatik hat einfach noch nie eine leere Variante davon vorgesehen.
Der Fehler tritt in der Regel erst in dem Moment zutage, in dem man versucht, eine ungenutzte e wegzulassen. Dieser Moment wird oft durch eine Meldung des Linters ausgelöst. Die ESLint-Regel no-unused-vars beinhaltet eine Option caughtErrors, und ab ESLint 9 steht diese Option standardmäßig auf "all" – das bedeutet, dass eine ungenutzte catch (e) ab sofort automatisch zu einem Lint-Fehler führt. Um diese Warnung zu beheben, leeren Entwickler instinktiv die Klammern, wie sie es bei einer Funktionssignatur tun würden, und genau da hält der Parser sie auf. Die tatsächlich richtige Lösung – die Klammern vollständig zu entfernen und catch { zu schreiben – ist die, zu der fast niemand zunächst greift, weil es in JavaScript ansonsten keinen Fall gibt, in dem „Kürzen“ bedeutet, etwas zu löschen anstatt nur zu leeren.
Der Fehler überlebt nie lange genug, um Spuren zu hinterlassen. Ein subtiler Logikfehler kann in die Produktion gelangen und einen Codebase monatelang plagen, bis er zu einer Art Kriegsgeschichte wird, die Entwickler jahrelang wiederholen. Dieser Fehler ist ganz anders: Es handelt sich um einen SyntaxError, der bereits beim Parsen sofort erkannt wird. Man sieht die wellenförmige Unterline, behebt ihn in Sekundenschnelle und macht ohne weiteres Nachdenken weiter. Es bleibt keine dauerhafte Erinnerung daran – und genau deshalb eignet er sich so gut als Interviewfrage. Sie prüft die Grenze zwischen Syntax, die man wirklich verinnerlicht hat, und Syntax, von der man nur annimmt, sie zu verstehen.
Eine Einschränkung, bevor Sie alle catch (e)-Anweisungen umschreiben: catch { } erlaubt es Ihnen, die Benennung des Fehlers auszulassen, nicht jedoch seine Bearbeitung. Die ES2019-Form existiert für legitime Logiken zum Testen und Rückfallverhalten, bei denen bereits das Erfassen des Fehlers als nützliches Signal dient. Ein leeres Catch-Körper, der einen echten Fehler einfach ignoriert, ist genauso problematisch wie immer – unabhängig davon, ob Klammern verwendet werden oder nicht.
Die bessere Antwort
Die Antwort, die das Interview auf Kurs gehalten hätte: „Das verursacht zu Zeitpunkt der Auswertung einen SyntaxError – genauer gesagt Unexpected token ')'. Nichts im Dateiinhalt wird überhaupt ausgeführt, nicht einmal der Code vor dem try-Block. Eine catch-Klausel hat nur zwei gültige Formen: catch (binding) { }, oder seit ES2019 die parameterlose catch { }. Leere Klammern passen zu keinem dieser Muster.“
Wichtige Punkte, die man sich merken sollte:
catch ()mit leeren Klammern war und bleibt in jeder Version von JavaScript ein SyntaxError.- Es gibt genau zwei gültige Formen:
catch (e) { }mit einer einzigen benannten Variable odercatch { }ohne Klammern überhaupt, eingeführt in ES2019.
catch (e) mit einem ungenutzten e zu verwenden, doch ESLint 9 markiert dies standardmäßig mit dem Flag no-unused-vars; die richtige Korrektur besteht darin, die Klammern zu entfernen, nicht den Inhalt darin.catch { } existiert für Fälle, in denen der Fehlerwert tatsächlich unnötig ist – er ist jedoch keine allgemeine Ausrede, um echte Fehler stillschweigend zu ignorieren.War die heftige Reaktion des Interviewers gerechtfertigt? Nur teilweise. Das Verhalten von try-catch im Laufzeitbetrieb stand nie zur Debatte – das war selbstverständlich. Was tatsächlich noch nie untersucht wurde, war die Grammatik an sich, einfach weil alltäglicher Arbeitscode einem selten dazu zwingt, sich damit auseinanderzusetzen. Heutzutage hat sich diese Gewohnheit umgekehrt: Wenn man ein nicht verwendetes e entfernen will, bedeutet das heute in der Regel auch das Löschen der Klammern zusammen damit, anstatt sie nur zu leeren.
Beim Kürzen einer Catch-Klausel sollten Sie die Klammern löschen – niemals sie nur leeren.
Zusätzliche Literatur
- Ein wiederverwendbares Toolkit für benutzerdefinierte Hooks für jedes neue React-Projekt – Entdecken Sie eine sorgfältig ausgewählte Sammlung von benutzerdefinierten React-Hooks, die Themen wie Speicherung, Verzögerung von Aktionen, Klicks und Datenabruf abdecken und wiederholenden Boilerplate-Code in neuen Projekten beseitigen.