Verwendung von instanceof in einer switch-Anweisung

Lesezeit: 5 Minuten

Benutzer-Avatar
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?

Benutzer-Avatar
Dimitri Pawlutin

Eine gute Option ist die Verwendung von constructor Eigentum 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:

  • error instanceof NotAllowedError ist true
  • error instanceof Error ist true

Prüfen dieser interessante Beitrag um constructor Eigentum.

  • 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

    – Nick Mitchell

    26. Januar 2019 um 6:03 Uhr

  • Geniale Idee! Austauschzustand und Etui.

    – Lancer.Yan

    27. Dezember 2019 um 4:24 Uhr

  • Typoskript erkennt dies derzeit nicht als Typwächter: github.com/microsoft/TypeScript/issues/37178

    – Vsevolod Golovanov

    18. Oktober 2021 um 10:42 Uhr

  • 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.

Bauen Sie Ihren Fehler beispielsweise so auf:

class NotAllowedError extends Error {
    constructor(message, status) {
        super(message);
        this.message = message;
        this.status = 403; // Forbidden error code
    }
}

Behandeln Sie Ihren Fehler wie folgt:

.catch((error) => {
  res.send(error.status);
});

  • 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.

1179530cookie-checkVerwendung von instanceof in einer switch-Anweisung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy