Exceptions personnalisées en JavaScript
puis-je définir des types personnalisés pour les exceptions définies par l'utilisateur dans JavaScript? Si je le peux, comment le ferais-je?
13 réponses
À Partir De 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;}
};
vous pouvez implémenter vos propres exceptions et leur manipulation par exemple comme ici:
// 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");
}
}
il existe une autre syntaxe pour saisir une exception dactylographiée, bien que cela ne fonctionne pas dans tous les navigateurs (par exemple pas dans 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");
}
vous devez créer une exception personnalisée qui hérite prototypiquement d'une erreur. Par exemple:
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;
il s'agit essentiellement d'une version simplifiée de ce que disfated affiché ci-dessus avec l'amélioration qui empile traces travail sur Firefox et d'autres navigateurs. Il satisfait aux mêmes tests qu'il a posté:
Utilisation:
throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");
et il se comportera est prévu:
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!
Oui. Vous pouvez lancer tout ce que vous voulez: des entiers, des cordes, des objets, n'importe quoi. Si vous voulez lancer un objet, créez simplement un nouvel objet, tout comme vous le feriez dans d'autres circonstances, puis lancez-le. la référence Javascript de Mozilla contient plusieurs exemples.
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error;
Cela permet l'utilisation comme..
try {
something();
} catch(e) {
if(e instanceof MyError)
doSomethingElse();
else if(e instanceof Error)
andNowForSomethingCompletelyDifferent();
}
Voici comment vous pouvez créer des erreurs personnalisées avec un comportement complètement identique à celui de Error
natif. Cette technique fonctionne seulement dans le Chrome et le noeud.js pour l'instant. Je recommande aussi de ne pas l'utiliser si vous ne comprenez pas ce qu'il fait.
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;
}
})();
comme une raison nous obtenons
/**
* 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)
, Alors vous pouvez l'utiliser comme ceci:
var NotImplementedError = Error.createCustromConstructor('NotImplementedError');
et utilisation NotImplementedError
comme vous le feriez Error
:
throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');
et il se comportera est prévu:
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!
Note ,que error.stack
fonctionne absolument correct et ne comprendra pas NotImplementedError
appel du constructeur (grâce à v8 Error.captureStackTrace()
).
Note. Il y a le laid eval()
. La seule raison pour laquelle il est utilisé est d'obtenir correct err.constructor.name
. Si vous n'en avez pas besoin, vous pouvez tout simplifier.
j'utilise souvent une approche avec héritage prototypique. La suppression de toString()
vous donne l'avantage que des outils comme Firebug enregistreront l'information réelle au lieu de [object Object]
sur la console pour les exceptions non récupérées.
utiliser instanceof
pour déterminer le type d'exception.
principal.js
// 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
Exception.js
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;
};
DuplicateIdException.js
ns.DuplicateIdException = function(message) {
this.name = 'Duplicate ID';
this.message = message;
};
ns.DuplicateIdException.prototype = new ns.Exception();
en bref:
-
si vous utilisez ES6 sans transpilers :
class CustomError extends Error { /* ... */}
Voir l'Extension de l'Erreur en Javascript avec ES6 syntaxe pour ce qui est actuellement la meilleure pratique
-
si vous utilisez Babel transpiler :
Option 1: utilisation de babel-plugin-transformer-builtin-étendre
Option 2: Faites-le vous-même (inspiré de cette même bibliothèque)
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);
-
si vous utilisez pure ES5 :
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; }
-
Alternatives: utilisation de Classtrophobic cadre
explication:
pourquoi étendre la classe D'erreur en utilisant ES6 et Babel est un problème?
parce qu'une instance de CustomError n'est plus reconnue comme telle.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
en fait, de la documentation officielle de Babel, vous ne peut pas étendre les classes intégrées JavaScript tels que Date
, Array
, DOM
ou Error
.
la question est décrite ici:
- Indigènes s'étend pauses HTMLELement, Array, et autres
- un objet de la classe qui s'étend par type de base comme tableau,nombre, objet,chaîne ou erreur n'est pas un instancede cette classe
Qu'en est-il des autres réponses SO?
toutes les réponses données corriger la question instanceof
mais vous perdez l'erreur régulière console.log
:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5"}
alors que l'utilisation de la méthode mentionnée ci-dessus, non seulement vous fixez la question instanceof
, mais vous gardez également l'erreur régulière console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
utilisez l'instruction lancer .
JavaScript ne se soucie pas de ce qu'est le type d'exception (comme Java). JavaScript juste des avis, il y a une exception et quand vous l'attrapez, vous pouvez "look" que l'exception "dit".
si vous avez différents types d'exception que vous devez lancer, je suggérerais d'utiliser des variables qui contiennent la chaîne de caractères/l'objet de l'exception, c'est-à-dire le message. Lorsque vous en avez besoin, utilisez "throw myException" et catch, comparez l'exception capturée à myException.
ES6
avec la nouvelle classe et extend keywords il est maintenant beaucoup plus facile:
class CustomError extends Error {
constructor(message) {
super(message);
//something
}
}
une alternative à la réponse de asselin pour une utilisation avec les classes ES2015
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;
}
}
maintenant nous définissons ajouter la raison ou n'importe quelles propriétés que nous voulons à l'objet d'erreur et le récupérer. En faisant l'erreur la plus raisonnable.
voir cet exemple dans le MDN.
si vous avez besoin de définir des erreurs multiples (tester le code ici !):
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 est principalement copié à partir de: Quelle est une bonne façon d'étendre L'erreur dans JavaScript?