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?
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?
Das einzige Standardfeld, das Error-Objekt hat, ist das Feld message
Eigentum. (Siehe MDN oder EcmaScript Sprachspezifikation, Abschnitt 15.11) Alles andere ist plattformspezifisch.
In den meisten Umgebungen wird die stack
Eigenschaft, sondern fileName
y lineNumber
sind für die Vererbung praktisch nicht zu gebrauchen.
Das ist also der minimalistische Ansatz:
function MyError(message) {
this.name = 'MyError';
this.message = message;
this.stack = (new Error()).stack;
}
MyError.prototype = new Error; // <-- remove this if you do not
// want MyError to be instanceof Error
Man könnte den Stack ausspähen, unerwünschte Elemente daraus entfernen und Informationen wie fileName und lineNumber extrahieren, aber dazu sind Informationen über die Plattform erforderlich, auf der JavaScript gerade läuft. In den meisten Fällen ist das unnötig - und Sie können es im Post-Mortem tun, wenn Sie wirklich wollen.
Safari ist eine bemerkenswerte Ausnahme. Es gibt keine stack
Eigenschaft, sondern die throw
Stichwortsätze sourceURL
y line
Eigenschaften des Objekts, das geworfen wird. Diese Dinge sind garantiert korrekt.
Die von mir verwendeten Testfälle finden Sie hier: JavaScript selbst erstellter Fehlerobjektvergleich .
Kurz gesagt:
Wenn Sie ES6 verwenden ohne Transporter :
class CustomError extends Error { /* ... */}
Wenn Sie Folgendes verwenden Babel-Umsetzer :
Option 1: Verwendung babel-plugin-transform-builtin-extend
Option 2: Selber machen (inspiriert durch dieselbe Bibliothek)
function CustomError(...args) {
const instance = Reflect.construct(Error, args);
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Reflect.setPrototypeOf(CustomError, Error);
Wenn Sie Folgendes verwenden ES5 pur :
function CustomError(message, fileName, lineNumber) {
var instance = new Error(message, fileName, lineNumber);
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
if (Object.setPrototypeOf){
Object.setPrototypeOf(CustomError, Error);
} else {
CustomError.__proto__ = Error;
}
Alternative: Verwendung Classtrophobie Rahmenwerk
説明することです:
Warum ist die Erweiterung der Fehlerklasse mit ES6 und Babel ein Problem?
Denn eine Instanz von CustomError wird nicht mehr als solche erkannt.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
In der offiziellen Dokumentation von Babel heißt es nämlich kann keine eingebauten JavaScript-Klassen erweitern wie zum Beispiel Date
, Array
, DOM
ou Error
.
Das Problem wird hier beschrieben:
Was ist mit den anderen SO-Antworten?
Alle gegebenen Antworten fixieren die instanceof
Problem, aber Sie verlieren den regulären Fehler console.log
:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error at CustomError (<anonymous>:4:19) at <anonymous>:1:5"}
Bei der oben erwähnten Methode hingegen fixieren Sie nicht nur die instanceof
Problem, aber Sie behalten auch den regulären Fehler console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
Edita: Bitte lesen Sie die Kommentare. Es stellt sich heraus, dies funktioniert nur gut in V8 (Chrome / Node.JS) Meine Absicht war es, eine Cross-Browser-Lösung, die in allen Browsern funktionieren würde, und bieten Stack-Trace, wo die Unterstützung gibt.
Edita: Ich habe dieses Community-Wiki erstellt, um mehr Bearbeitung zu ermöglichen.
Lösung für V8 (Chrome / Node.JS), funktioniert in Firefox und kann so modifiziert werden, dass sie im IE weitgehend korrekt funktioniert (siehe Ende des Beitrags)
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype // Make this an instanceof Error.
Error.call(this) // Does not seem necessary. Perhaps remove this line?
Error.captureStackTrace(this, this.constructor) // Creates the this.stack getter
this.name = this.constructor.name; // Used to cause messages like "UserError: message" instead of the default "Error: message"
this.message = message; // Used to set the message
}
Ursprünglicher Beitrag zu "Zeig mir den Code!"
Kurzfassung:
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = message
}
Ich behalte this.constructor.prototype.__proto__ = Error.prototype
innerhalb der Funktion, um den gesamten Code zusammenzuhalten. Sie können aber auch ersetzen this.constructor
con UserError
und das ermöglicht es Ihnen, den Code außerhalb der Funktion zu verschieben, so dass er nur einmal aufgerufen wird.
Wenn Sie sich für diesen Weg entscheiden, stellen Sie sicher, dass Sie diese Leitung anrufen vor das erste Mal, wenn Sie werfen UserError
.
Dieser Vorbehalt gilt nicht für die Funktion, da Funktionen unabhängig von der Reihenfolge zuerst erstellt werden. Sie können die Funktion also ohne Probleme an das Ende der Datei verschieben.
Browser-Kompatibilität
Funktioniert in Firefox und Chrome (und Node.JS) und erfüllt alle Versprechen.
Internet Explorer schlägt in folgenden Fällen fehl
Fehler haben keine err.stack
Es ist also nicht meine Schuld".
Error.captureStackTrace(this, this.constructor)
gibt es nicht, also müssen Sie etwas anderes tun wie
if(Error.captureStackTrace) // AKA if not IE
Error.captureStackTrace(this, this.constructor)
toString
hört auf zu existieren, wenn Sie die Unterklasse Error
. Sie müssen also auch hinzufügen.
else
this.toString = function () { return this.name + ': ' + this.message }
IE wird nicht berücksichtigt UserError
zu sein instanceof Error
es sei denn, Sie führen das folgende Programm einige Zeit vor dem throw UserError
UserError.prototype = Error.prototype
への Vermeiden Sie die Floskeln für die verschiedenen Fehlertypen, habe ich die Weisheit einiger Lösungen zu einem createErrorType
Funktion:
function createErrorType(name, init) {
function E(message) {
if (!Error.captureStackTrace)
this.stack = (new Error()).stack;
else
Error.captureStackTrace(this, this.constructor);
this.message = message;
init && init.apply(this, arguments);
}
E.prototype = new Error();
E.prototype.name = name;
E.prototype.constructor = E;
return E;
}
Dann können Sie neue Fehlertypen einfach definieren wie folgt:
var NameError = createErrorType('NameError', function (name, invalidChar) {
this.message = 'The name ' + name + ' may not contain ' + invalidChar;
});
var UnboundError = createErrorType('UnboundError', function (variableName) {
this.message = 'Variable ' + variableName + ' is not bound';
});
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.