528 Stimmen

Was ist ein guter Weg, um Error in JavaScript zu erweitern?

Ich möchte einige Dinge in meinem JS-Code werfen und ich möchte, dass sie instanceof Error sind, aber ich möchte auch, dass sie etwas anderes sind.

In Python würde man normalerweise die Unterklasse Exception.

Was ist bei JS zu tun?

2voto

John Punkte 6674

Mohsen hat eine großartige Antwort oben in ES6, die den Namen setzt, aber wenn Sie TypeScript verwenden oder wenn Sie in der Zukunft leben, wo hoffentlich diese Vorschlag für öffentliche und private Klassenfelder die Stufe 3 als Vorschlag hinter sich gelassen hat und als Teil von ECMAScript/JavaScript in die Stufe 4 aufgestiegen ist, dann sollten Sie wissen, dass diese dann nur noch ein wenig kürzer ist. In Stufe 3 beginnen die Browser mit der Implementierung von Funktionen. Wenn Ihr Browser dies unterstützt, könnte der folgende Code funktionieren. (Getestet mit dem neuen Edge-Browser v81 scheint er gut zu funktionieren). Seien Sie jedoch gewarnt, dass es sich hierbei um eine instabile Funktion handelt, die mit Vorsicht zu genießen ist, und Sie sollten immer die Browserunterstützung für instabile Funktionen überprüfen. Dieser Beitrag ist hauptsächlich für diejenigen gedacht, die in der Zukunft leben, wenn die Browser dies unterstützen. Um die Unterstützung zu überprüfen, prüfen Sie MDN y Kann ich die . Es hat derzeit 66% Unterstützung auf dem Browsermarkt, was ein Fortschritt ist, aber nicht so toll. Wenn Sie es also wirklich jetzt benutzen wollen und nicht warten wollen, benutzen Sie einen Transpiler wie Babel oder etwas wie TypScript .

class EOFError extends Error { 
  name="EOFError"
}
throw new EOFError("Oops errored");

Vergleichen Sie dies mit einem namenlosen Fehler, dessen Name nicht protokolliert wird, wenn er ausgelöst wird.

class NamelessEOFError extends Error {}
throw new NamelessEOFError("Oops errored");

1voto

B T Punkte 51689

Der Weg, um dies richtig zu tun ist, um das Ergebnis der Anwendung aus dem Konstruktor zurück, sowie die Einstellung des Prototyps in der üblichen komplizierten javascripty Weg:

function MyError() {
    var tmp = Error.apply(this, arguments);
    tmp.name = this.name = 'MyError'

    this.stack = tmp.stack
    this.message = tmp.message

    return this
}
    var IntermediateInheritor = function() {}
        IntermediateInheritor.prototype = Error.prototype;
    MyError.prototype = new IntermediateInheritor()

var myError = new MyError("message");
console.log("The message is: '"+myError.message+"'") // The message is: 'message'
console.log(myError instanceof Error)                // true
console.log(myError instanceof MyError)              // true
console.log(myError.toString())                      // MyError: message
console.log(myError.stack)                           // MyError: message \n 
                                                     // <stack trace ...>

Die einzigen Probleme, die sich bei dieser Vorgehensweise ergeben (ich habe sie ein wenig überarbeitet), sind folgende

  • andere Eigenschaften als stack y message sind nicht enthalten in MyError y
  • der Stacktrace enthält eine zusätzliche Zeile, die eigentlich nicht notwendig ist.

Das erste Problem könnte behoben werden, indem alle nicht aufzählbaren Fehlereigenschaften mit Hilfe des Tricks in dieser Antwort durchlaufen werden: Ist es möglich, die nicht aufzählbaren geerbten Eigenschaftsnamen eines Objekts abzurufen? , aber das wird von ie<9 nicht unterstützt. Das zweite Problem könnte durch Herausreißen dieser Zeile im Stacktrace gelöst werden, aber ich bin mir nicht sicher, wie man das sicher macht (vielleicht einfach die zweite Zeile von e.stack.toString() entfernen?)

1voto

Amarpreet Singh Punkte 21

Das Snippet zeigt alles.

function add(x, y) {
      if (x && y) {
        return x + y;
      } else {
        /**
         * 
         * the error thrown will be instanceof Error class and InvalidArgsError also
         */
        throw new InvalidArgsError();
        // throw new Invalid_Args_Error(); 
      }
    }

    // Declare custom error using using Class
    class Invalid_Args_Error extends Error {
      constructor() {
        super("Invalid arguments");
        Error.captureStackTrace(this);
      }
    }

    // Declare custom error using Function
    function InvalidArgsError(message) {
      this.message = `Invalid arguments`;
      Error.captureStackTrace(this);
    }
    // does the same magic as extends keyword
    Object.setPrototypeOf(InvalidArgsError.prototype, Error.prototype);

    try{
      add(2)
    }catch(e){
      // true
      if(e instanceof Error){
        console.log(e)
      }
      // true
      if(e instanceof InvalidArgsError){
        console.log(e)
      }
    }

1voto

Daniel Punkte 28370

Meine vorgeschlagene Lösung ist die Verwendung der .name Eigenschaft des Fehlers zur Unterscheidung zwischen den Fehlertypen anstelle von instancof

Das beantwortet die Frage nicht ganz, aber ich denke, es ist eine vernünftige Lösung, jedenfalls für einige Szenarien.

Der Vorteil, den ich gesehen habe, ist die Möglichkeit, eine instanceof CustomError ist, dass Sie in Ihrem Versprechen-Catch-Handler eine benutzerdefinierte Behandlung vornehmen können.

Zum Beispiel:

class CustomError extends Error {/** ... **/}

axios
  .post(url, payload)
  .then(data => {
    if (!data.loggedIn) throw CustomError("not logged in");
    return data;
  })
  .catch(error => {
    if (error instanceof CustomError) {/** custom handling of error*//}
    throw error
  })

Wenn es das ist, was Sie zu erreichen versuchen, sind Sie mit dem .name aber auch Parameter:

export const ERROR_NOT_LOGGED_IN = "ERROR_NOT_LOGGED_IN";

axios
  .post(url, payload)
  .then(data => {
    if (!data.loggedIn) throw Error("not logged in").name=ERROR_NOT_LOGGED_IN ;
    return data;
  })
  .catch(error => {
    if (error.name === ERROR_NOT_LOGGED_IN) {/** custom handling of error*//}
    throw error
  })

0voto

bormat Punkte 1191

Wenn Sie sich nicht um die Leistung bei Fehlern kümmern, ist dies das Mindeste, was Sie tun können

Object.setPrototypeOf(MyError.prototype, Error.prototype)
function MyError(message) {
    const error = new Error(message)
    Object.setPrototypeOf(error, MyError.prototype);
    return error
}

Sie können es ohne new nur MyError(message) verwenden

Durch die Änderung des Prototyps nach dem Aufruf des Konstruktors Error müssen wir den Callstack und die Meldung nicht setzen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X