Kann ich benutzerdefinierte Typen für benutzerdefinierte Ausnahmen in JavaScript definieren? Wenn ja, wie würde ich das machen?
Kann ich benutzerdefinierte Typen für benutzerdefinierte Ausnahmen in JavaScript definieren? Wenn ja, wie würde ich das machen?
Antworten:
Von WebReference :
throw {
name: "System Error",
level: "Show Stopper",
message: "Error detected. Please contact the system administrator.",
htmlMessage: "Error detected. Please contact the <a href=\"mailto:sysadmin@acme-widgets.com\">system administrator</a>.",
toString: function(){return this.name + ": " + this.message;}
};
catch (e) { if (e instanceof TypeError) { … } else { throw e; } }
⦃⦄ oder catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }
⦃⦄.
Sie sollten eine benutzerdefinierte Ausnahme erstellen, die prototypisch von Error erbt. Beispielsweise:
function InvalidArgumentException(message) {
this.message = message;
// Use V8's native method if available, otherwise fallback
if ("captureStackTrace" in Error)
Error.captureStackTrace(this, InvalidArgumentException);
else
this.stack = (new Error()).stack;
}
InvalidArgumentException.prototype = Object.create(Error.prototype);
InvalidArgumentException.prototype.name = "InvalidArgumentException";
InvalidArgumentException.prototype.constructor = InvalidArgumentException;
Dies ist im Grunde eine vereinfachte Version von dem, was oben veröffentlicht wurde, mit der Verbesserung, dass Stack-Traces in Firefox und anderen Browsern funktionieren. Es erfüllt die gleichen Tests, die er veröffentlicht hat:
Verwendung:
throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");
Und es wird sich verhalten wird erwartet:
err instanceof InvalidArgumentException // -> true
err instanceof Error // -> true
InvalidArgumentException.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err) // -> true
err.constructor.name // -> InvalidArgumentException
err.name // -> InvalidArgumentException
err.message // -> Not yet...
err.toString() // -> InvalidArgumentException: Not yet...
err.stack // -> works fine!
Sie können Ihre eigenen Ausnahmen und deren Behandlung beispielsweise wie folgt implementieren:
// define exceptions "classes"
function NotNumberException() {}
function NotPositiveNumberException() {}
// try some code
try {
// some function/code that can throw
if (isNaN(value))
throw new NotNumberException();
else
if (value < 0)
throw new NotPositiveNumberException();
}
catch (e) {
if (e instanceof NotNumberException) {
alert("not a number");
}
else
if (e instanceof NotPositiveNumberException) {
alert("not a positive number");
}
}
Es gibt eine andere Syntax zum Abfangen einer typisierten Ausnahme, obwohl dies nicht in jedem Browser funktioniert (z. B. nicht im IE):
// define exceptions "classes"
function NotNumberException() {}
function NotPositiveNumberException() {}
// try some code
try {
// some function/code that can throw
if (isNaN(value))
throw new NotNumberException();
else
if (value < 0)
throw new NotPositiveNumberException();
}
catch (e if e instanceof NotNumberException) {
alert("not a number");
}
catch (e if e instanceof NotPositiveNumberException) {
alert("not a positive number");
}
Ja. Sie können alles werfen, was Sie wollen: Ganzzahlen, Zeichenfolgen, Objekte, was auch immer. Wenn Sie ein Objekt werfen möchten, erstellen Sie einfach ein neues Objekt, genau wie Sie es unter anderen Umständen erstellen würden, und werfen Sie es dann. Mozillas Javascript-Referenz enthält mehrere Beispiele.
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error;
Dies ermöglicht die Verwendung wie ..
try {
something();
} catch(e) {
if(e instanceof MyError)
doSomethingElse();
else if(e instanceof Error)
andNowForSomethingCompletelyDifferent();
}
e instanceof Error
wäre falsch.
e instanceof MyError
dies wahr wäre, würde die else if(e instanceof Error)
Aussage niemals bewertet werden.
else if(e instanceof Error)
wäre der letzte Fang. Wahrscheinlich gefolgt von einem einfachen else
(was ich nicht aufgenommen habe). So ähnlich wie default:
in einer switch-Anweisung, aber für Fehler.
Zusamenfassend:
Wenn Sie ES6 ohne Transpiler verwenden :
class CustomError extends Error { /* ... */}
Informationen zur aktuellen Best Practice finden Sie unter Erweitern des Fehlers in Javascript mit ES6-Syntax
Wenn Sie den Babel-Transpiler verwenden :
Option 1: Verwenden Sie Babel-Plugin-Transform-Builtin-Extend
Option 2: Mach es selbst (inspiriert von derselben 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 reines ES5 verwenden :
function CustomError(message, fileName, lineNumber) {
const 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: Verwenden Sie das Classtrophobic- Framework
Erläuterung:
Warum ist die Erweiterung der Fehlerklasse mit ES6 und Babel ein Problem?
Weil eine Instanz von CustomError nicht mehr als solche erkannt wird.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
In der Tat, von der offiziellen Dokumentation von Babel, Sie können nicht verlängern jede integrierte JavaScript - Klassen wie Date
, Array
, DOM
oder Error
.
Das Problem wird hier beschrieben:
Was ist mit den anderen SO-Antworten?
Alle gegebenen Antworten beheben das 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"}
Mit der oben genannten Methode beheben Sie nicht nur das instanceof
Problem, sondern behalten auch den regulären Fehler bei console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
Hier erfahren Sie, wie Sie benutzerdefinierte Fehler erstellen können, die vollständig mit dem Error
Verhalten von Native identisch sind . Diese Technik funktioniert nur in Chrome und node.js für jetzt. Ich würde es auch nicht empfehlen, wenn Sie nicht verstehen, was es tut.
Error.createCustromConstructor = (function() {
function define(obj, prop, value) {
Object.defineProperty(obj, prop, {
value: value,
configurable: true,
enumerable: false,
writable: true
});
}
return function(name, init, proto) {
var CustomError;
proto = proto || {};
function build(message) {
var self = this instanceof CustomError
? this
: Object.create(CustomError.prototype);
Error.apply(self, arguments);
Error.captureStackTrace(self, CustomError);
if (message != undefined) {
define(self, 'message', String(message));
}
define(self, 'arguments', undefined);
define(self, 'type', undefined);
if (typeof init == 'function') {
init.apply(self, arguments);
}
return self;
}
eval('CustomError = function ' + name + '() {' +
'return build.apply(this, arguments); }');
CustomError.prototype = Object.create(Error.prototype);
define(CustomError.prototype, 'constructor', CustomError);
for (var key in proto) {
define(CustomError.prototype, key, proto[key]);
}
Object.defineProperty(CustomError.prototype, 'name', { value: name });
return CustomError;
}
})();
Als Ergebnis bekommen wir
/**
* name The name of the constructor name
* init User-defined initialization function
* proto It's enumerable members will be added to
* prototype of created constructor
**/
Error.createCustromConstructor = function(name, init, proto)
Dann können Sie es so verwenden:
var NotImplementedError = Error.createCustromConstructor('NotImplementedError');
Und verwenden NotImplementedError
Sie wie Sie würden Error
:
throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');
Und es wird sich verhalten wird erwartet:
err instanceof NotImplementedError // -> true
err instanceof Error // -> true
NotImplementedError.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err) // -> true
err.constructor.name // -> NotImplementedError
err.name // -> NotImplementedError
err.message // -> Not yet...
err.toString() // -> NotImplementedError: Not yet...
err.stack // -> works fine!
Beachten Sie, dass dies error.stack
absolut korrekt funktioniert und keinen NotImplementedError
Konstruktoraufruf enthält (dank v8 Error.captureStackTrace()
).
Hinweis. Es ist hässlich eval()
. Der einzige Grund, warum es verwendet wird, ist, richtig zu werden err.constructor.name
. Wenn Sie es nicht brauchen, können Sie alles ein bisschen vereinfachen.
Error.apply(self, arguments)
wird angegeben, um nicht zu arbeiten . Ich empfehle stattdessen den Stack-Trace zu kopieren, der browserübergreifend kompatibel ist.
Ich verwende oft einen Ansatz mit prototypischer Vererbung. Das Überschreiben toString()
bietet Ihnen den Vorteil, dass Tools wie Firebug die tatsächlichen Informationen protokollieren und nicht [object Object]
für nicht erfasste Ausnahmen an der Konsole.
Verwenden Sie instanceof
diese Option , um die Art der Ausnahme zu bestimmen.
// just an exemplary namespace
var ns = ns || {};
// include JavaScript of the following
// source files here (e.g. by concatenation)
var someId = 42;
throw new ns.DuplicateIdException('Another item with ID ' +
someId + ' has been created');
// Firebug console:
// uncaught exception: [Duplicate ID] Another item with ID 42 has been created
ns.Exception = function() {
}
/**
* Form a string of relevant information.
*
* When providing this method, tools like Firebug show the returned
* string instead of [object Object] for uncaught exceptions.
*
* @return {String} information about the exception
*/
ns.Exception.prototype.toString = function() {
var name = this.name || 'unknown';
var message = this.message || 'no description';
return '[' + name + '] ' + message;
};
ns.DuplicateIdException = function(message) {
this.name = 'Duplicate ID';
this.message = message;
};
ns.DuplicateIdException.prototype = new ns.Exception();
Verwenden Sie die throw- Anweisung.
JavaScript ist es egal, welcher Ausnahmetyp ist (wie Java). JavaScript bemerkt nur, es gibt eine Ausnahme und wenn Sie es abfangen, können Sie "schauen", was die Ausnahme "sagt".
Wenn Sie verschiedene Ausnahmetypen haben, die Sie auslösen müssen, würde ich empfehlen, Variablen zu verwenden, die die Zeichenfolge / das Objekt der Ausnahme enthalten, z. B. die Nachricht. Wo Sie es brauchen, verwenden Sie "throw myException" und vergleichen Sie im catch die abgefangene Ausnahme mit myException.
Siehe dieses Beispiel im MDN.
Wenn Sie mehrere Fehler definieren müssen (testen Sie den Code hier !):
function createErrorType(name, initFunction) {
function E(message) {
this.message = message;
if (Error.captureStackTrace)
Error.captureStackTrace(this, this.constructor);
else
this.stack = (new Error()).stack;
initFunction && initFunction.apply(this, arguments);
}
E.prototype = Object.create(Error.prototype);
E.prototype.name = name;
E.prototype.constructor = E;
return E;
}
var InvalidStateError = createErrorType(
'InvalidStateError',
function (invalidState, acceptedStates) {
this.message = 'The state ' + invalidState + ' is invalid. Expected ' + acceptedStates + '.';
});
var error = new InvalidStateError('foo', 'bar or baz');
function assert(condition) { if (!condition) throw new Error(); }
assert(error.message);
assert(error instanceof InvalidStateError);
assert(error instanceof Error);
assert(error.name == 'InvalidStateError');
assert(error.stack);
error.message;
Code wird meistens kopiert von: Was ist ein guter Weg, um Fehler in JavaScript zu erweitern?
Eine Alternative zur Antwort von Asselin zur Verwendung mit ES2015-Klassen
class InvalidArgumentException extends Error {
constructor(message) {
super();
Error.captureStackTrace(this, this.constructor);
this.name = "InvalidArgumentException";
this.message = message;
}
}
//create error object
var error = new Object();
error.reason="some reason!";
//business function
function exception(){
try{
throw error;
}catch(err){
err.reason;
}
}
Jetzt setzen wir den Grund oder die gewünschten Eigenschaften zum Fehlerobjekt und rufen es ab. Indem Sie den Fehler vernünftiger machen.