Verwendung von instanceof in einer switch-Anweisung
Lesezeit: 5 Minuten
alexes
Ich verwende benutzerdefinierte Fehler (es6-Fehler), sodass ich Fehler basierend auf ihrer Klasse wie folgt behandeln kann:
import { DatabaseEntryNotFoundError, NotAllowedError } from 'customError';
function fooRoute(req, res) {
doSomethingAsync()
.then(() => {
// on resolve / success
return res.send(200);
})
.catch((error) => {
// on reject / failure
if (error instanceof DatabaseEntryNotFoundError) {
return res.send(404);
} else if (error instanceof NotAllowedError) {
return res.send(400);
}
log('Failed to do something async with an unspecified error: ', error);
return res.send(500);
};
}
Jetzt würde ich lieber einen Schalter für diese Art von Fluss verwenden, was zu etwas führt wie:
import { DatabaseEntryNotFoundError, NotAllowedError } from 'customError';
function fooRoute(req, res) {
doSomethingAsync()
.then(() => {
// on resolve / success
return res.send(200);
})
.catch((error) => {
// on reject / failure
switch (error instanceof) {
case NotAllowedError:
return res.send(400);
case DatabaseEntryNotFoundError:
return res.send(404);
default:
log('Failed to do something async with an unspecified error: ', error);
return res.send(500);
}
});
}
Instanzvon geht so aber nicht. Letzteres fällt also aus.
Gibt es eine Möglichkeit, eine Instanz in einer switch-Anweisung auf ihre Klasse zu überprüfen?
Dimitri Pawlutin
Eine gute Option ist die Verwendung von constructorEigentum des Objektes:
// on reject / failure
switch (error.constructor) {
case NotAllowedError:
return res.send(400);
case DatabaseEntryNotFoundError:
return res.send(404);
default:
log('Failed to do something async with an unspecified error: ', error);
return res.send(500);
}
Beachten Sie, dass die constructor muss genau mit dem übereinstimmen, mit dem das Objekt erstellt wurde (angenommen error ist eine Instanz von NotAllowedError und NotAllowedError ist eine Unterklasse von Error):
error.constructor === NotAllowedError ist true
error.constructor === Error ist false
Dies unterscheidet sich von instanceofdie auch mit der Superklasse mithalten kann:
Ich mag das mehr als meine eigene Antwort. Auf diese Weise muss ich nicht gegen Zeichenfolgen prüfen, sondern kann gegen das tatsächliche Objekt prüfen. Ich bin mir aber nicht sicher, was technisch sinnvoller wäre.
– alexes
31. März 2016 um 11:58 Uhr
Es ist einfacher, die Konstruktorfunktion zu schreiben als ihren Namen: die Autovervollständigung :).
– Dmitri Pawlutin
31. März 2016 um 11:59 Uhr
Ein Wort der Warnung dazu: Wenn Sie mit Babel transpilieren, stellen Sie möglicherweise fest, dass die obige switch-Anweisung immer den Standardfall trifft. Babel erlaubt es Ihnen nicht, eingebaute Typen wie error ohne using abzuleiten babel-plugin-transformieren-integriert-erweitern
– Edward Woolhouse
6. August 2018 um 7:39 Uhr
@EdwardWoolhouse gilt das auch jetzt noch? Gut, dass ich gesehen habe, dass du warnst
– Moe Elsharif
17. August 2018 um 15:30 Uhr
Das Typoskript versteht diese Syntax nicht 🙁
– Mor Bargig
20. Mai um 0:35 Uhr
Problemumgehung, um if-else zu vermeiden. Gefunden hier
switch (true) {
case error instanceof NotAllowedError:
return res.send(400);
case error instanceof DatabaseEntryNotFoundError:
return res.send(404);
default:
log('Failed to do something async with an unspecified error: ', error);
return res.send(500);
}
Dies sollte die Antwort sein, da es mit allen Geschmacksrichtungen/Geschmacksrichtungen von JS „abwärtskompatibel“ ist. Die Verwendung von error.constructor funktioniert nicht in allen Browsern und Versionen von Babel
Wie ist das besser als das if else? Ich dachte, der ganze Punkt würde sich nicht wiederholen error?
– David Mulder
25. Januar um 16:21 Uhr
@DavidMulder von if-else sollten Sie viel mehr Zeichen hinzufügen und viel mehr Code mit geschweiften Klammern lesen. Alles wird noch schlimmer, wenn Sie Code für mehrere Fälle benötigen (in der Switch-Case-Out-of-the-Box-Funktion). Bei if-else sollten Sie “||” hinzufügen Zustand dann. Es ist also einfach angenehm zu lesen und zu schreiben 🥂
– ya_dimon
26. Januar um 4:54
Eine Alternative zu diesem Schalterfall besteht darin, nur ein Statusfeld im Konstruktor des Fehlers zu haben.
Sie gehen davon aus, dass der Aufrufer eine Funktion ist, die die HTTP-Kommunikation verarbeitet. Die Kopplungslogik des Aufrufers mit der aufgerufenen Funktion ist im Allgemeinen keine gute Idee. Angenommen, der Anrufer hat einen Sonderfall, in dem die Antwort trotz der 200 lautet NotAllowed error Die Funktion, die den Fehler auslöst, muss nun den Unterschied verstehen und die richtige ausgeben NotAllowedError.
– alexes
22. August 2018 um 9:31 Uhr
@AlexTes Ich habe Mühe zu verstehen, was falsch daran ist, anzunehmen, dass der Aufrufer eine Funktion ist, die die HTTP-Kommunikation verarbeitet. Was könnte ein res.send unter Berücksichtigung der ursprünglichen Frage noch sein? Außerdem erwähnen Sie einen Sonderfall um einen 200-Fehler herum. Sie könnten ein if im catch hinzufügen, um damit umzugehen. Meine Absicht war hier, eine alternative Lösung für die ursprüngliche Frage zu geben. Es tut mir leid, wenn ich das falsch verstehe, aber es scheint, als würden Sie meine Antwort auf einen ganz anderen Bereich anwenden?
– Lachlan Young
23. August 2018 um 6:01 Uhr
Mein einziger Punkt ist, dass es schöner ist doSomethingAsync nichts darüber zu wissen, was es heißt. Da wirft es den Fehler, und die Art und Weise der fooRoute funktioniert, hängt davon ab, was in dem Fehler steht, doSomethingAsync Jetzt muss möglicherweise bewusst sein, wie fooRoute funktioniert, um den Fehler mit dem richtigen Statuscode auszulösen. Sie würden zusammengebunden werden.
– alexes
23. August 2018 um 20:41 Uhr
Ah! Danke für die Erklärung Alex, das ist ein wirklich guter Punkt. Mir war nicht klar, dass Sie es so getrennt halten wollten, ich nehme an, es ist einfach eine bessere Übung.
– Lachlan Young
23. August 2018 um 23:39 Uhr
Ich kann keine Kommentare schreiben, also musste ich eine Antwort schreiben.
Wenn Sie das Konstruktorobjekt verwenden, um den Instanztyp eines Objekts zu bestimmen, sollten Sie den folgenden Absatz beachten Webdokumentation für Mozilla-Entwickler:
Es gibt nichts, was die Konstruktor-Eigenschaft davor schützt, neu zugewiesen oder gespiegelt zu werden, daher sollte ihre Verwendung zur Erkennung des Typs einer Variablen normalerweise zugunsten weniger fragiler Methoden wie instanceof und Symbol.toStringTag für Objekte oder typeof für Primitive vermieden werden.
Ein weiteres Problem bei der Verwendung von Konstruktorobjekten ist, wenn Sie später einige neue Unterklassen bereits vorhandener Klassen erstellen. Denn wenn der Typ auf diese Weise überprüft wird, werden Objekte von Unterklassen nicht als Instanzen der übergeordneten Klasse erkannt.
Allerdings bietet diese Option eine gute Möglichkeit, den Objekttyp innerhalb der switch-Anweisung zu bestimmen, solange Sie sich dabei der Risiken bewusst sind.
11795300cookie-checkVerwendung von instanceof in einer switch-Anweisungyes