Je veux ajouter des éléments dans mon code JS et je veux qu’ils soient des exemples d’erreur, mais je veux aussi qu’ils soient quelque chose d’autre.
En Python, en général, on sous-classe Exception.
Quelle est la bonne chose à faire dans JS?
Le seul objet d'erreur de champ standard est la propriété message
. (Voir MDN ou Spécification du langage EcmaScript, section 15.11) Tout le reste est spécifique à la plate-forme.
Les environnements Mosts définissent la propriété stack
, mais fileName
et lineNumber
sont pratiquement inutiles pour être utilisés en héritage.
Ainsi, l'approche minimaliste est la suivante:
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
Vous pouvez détecter la pile, en décaler les éléments indésirables et extraire des informations telles que fileName et lineNumber, mais cela nécessite des informations sur la plate-forme sur laquelle JavaScript est en cours d'exécution. La plupart des cas sont inutiles - et vous pouvez le faire en post-mortem si vous le souhaitez vraiment.
Safari est une exception notable. Il n'y a pas de propriété stack
, mais le mot clé throw
définit les propriétés sourceURL
et line
de l'objet qui est généré. Ces choses sont garanties d'être correctes.
Les cas de test que j'ai utilisés peuvent être trouvés ici: JavaScript auto-fabriqué Erreur comparaison d'objets .
En ES6:
class MyError extends Error {
constructor(message) {
super(message);
this.name = 'MyError';
}
}
Edit: S'il vous plaît lire les commentaires. Il s'avère que cela ne fonctionne que dans V8 (Chrome/Node.JS). Mon intention était de fournir une solution inter-navigateurs, qui fonctionnerait dans tous les navigateurs, et de fournir une trace de la pile là où l'assistance est disponible.
Edit: J'ai créé ce wiki de communauté pour permettre plus de modifications.
La solution pour V8 (Chrome/Node.JS) fonctionne dans Firefox et peut être modifiée pour fonctionner principalement correctement dans IE. (voir fin de post)
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
}
Article original sur "Montre-moi le code!"
Version courte:
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = message
}
Je garde this.constructor.prototype.__proto__ = Error.prototype
dans la fonction pour garder tout le code ensemble. Mais vous pouvez également remplacer this.constructor
par UserError
et cela vous permet de déplacer le code en dehors de la fonction, de sorte qu'il ne soit appelé qu'une fois.
Si vous choisissez cette voie, assurez-vous d'appeler cette ligne avant la première fois que vous lancez UserError
.
Cette mise en garde ne s'applique pas à la fonction, car les fonctions sont créées en premier, peu importe l'ordre. Ainsi, vous pouvez déplacer la fonction à la fin du fichier, sans problème.
Compatibilité du navigateur
Fonctionne dans Firefox et Chrome (et Node.JS) et remplit toutes les promesses.
Internet Explorer échoue dans les cas suivants
Les erreurs n'ont pas err.stack
pour commencer, donc "ce n'est pas de ma faute".
Error.captureStackTrace(this, this.constructor)
n'existe pas, vous devez donc faire autre chose, par exemple
if(Error.captureStackTrace) // AKA if not IE
Error.captureStackTrace(this, this.constructor)
toString
cesse d'exister lorsque vous sous-classe Error
. Donc, vous devez également ajouter.
else
this.toString = function () { return this.name + ': ' + this.message }
Internet Explorer ne considérera pas UserError
comme un instanceof Error
à moins que vous n'exécutiez ce qui suit avant le throw UserError
UserError.prototype = Error.prototype
En bref:
Si vous utilisez ES6 sans transpilers:
class CustomError extends Error { /* ... */}
Si vous utilisez le transpiler Babel:
Option 1: utilisez babel-plugin-transform-builtin-extend
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) {
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: utilisez le cadre Classtrophobic
Explication:
Pourquoi l'extension de la classe Error avec ES6 et Babel pose-t-elle un problème?
Car une instance de CustomError n'est plus reconnue en tant que telle.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
En fait, dans la documentation officielle de Babel, vous ne pouvez pas étendre les classes JavaScript intégrées tels que Date
, Array
, DOM
ou Error
.
Le problème est décrit ici:
Qu'en est-il des autres SO réponses?
Toutes les réponses données résolvent le problème instanceof
mais vous perdez l’erreur habituelle 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 vous utilisez la méthode mentionnée ci-dessus, non seulement vous corrigez le problème instanceof
mais vous conservez également l'erreur habituelle console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
Pour éviter le passe-partout pour chaque type d'erreur différent, j'ai combiné la sagesse de certaines des solutions dans une fonction createErrorType
:
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;
}
Ensuite, vous pouvez définir facilement de nouveaux types d’erreur comme suit:
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';
});
En 2018, je pense que c'est la meilleure façon; qui prend en charge IE9 + et les navigateurs modernes.
UPDATE: Voir this test et repo pour une comparaison sur différentes implémentations.
function CustomError(message) {
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: 'CustomError'
});
Object.defineProperty(this, 'message', {
enumerable: false,
writable: true,
value: message
});
if (Error.hasOwnProperty('captureStackTrace')) { // V8
Error.captureStackTrace(this, CustomError);
} else {
Object.defineProperty(this, 'stack', {
enumerable: false,
writable: false,
value: (new Error(message)).stack
});
}
}
if (typeof Object.setPrototypeOf === 'function') {
Object.setPrototypeOf(CustomError.prototype, Error.prototype);
} else {
CustomError.prototype = Object.create(Error.prototype, {
constructor: { value: CustomError }
});
}
Notez également que la propriété __proto__
est deprecated qui est largement utilisée dans d'autres réponses.
Par souci d’exhaustivité - du fait qu’aucune des réponses précédentes n’a mentionné cette méthode - si vous travaillez avec Node.js et n’avez pas à vous soucier de la compatibilité du navigateur, l’effet souhaité est assez facile à obtenir avec la inherits
du module util
( documents officiels ici ).
Par exemple, supposons que vous souhaitiez créer une classe d'erreur personnalisée qui prend un code d'erreur en premier argument et le message d'erreur en deuxième argument:
fichier custom-error.js:
'use strict';
var util = require('util');
function CustomError(code, message) {
Error.captureStackTrace(this, CustomError);
this.name = CustomError.name;
this.code = code;
this.message = message;
}
util.inherits(CustomError, Error);
module.exports = CustomError;
Maintenant, vous pouvez instancier et passer/jeter votre CustomError
:
var CustomError = require('./path/to/custom-error');
// pass as the first argument to your callback
callback(new CustomError(404, 'Not found!'));
// or, if you are working with try/catch, throw it
throw new CustomError(500, 'Server Error!');
Notez qu'avec cet extrait, la trace de la pile aura le nom de fichier et la ligne corrects, et l'instance d'erreur aura le nom correct!
Cela est dû à l'utilisation de la méthode captureStackTrace
, qui crée une propriété stack
sur l'objet cible (dans ce cas, la CustomError
étant instanciée). Pour plus de détails sur son fonctionnement, consultez la documentation ici .
La réponse fortement votée de Crescent Fresh est trompeuse. Bien que ses avertissements ne soient pas valides, il n’adresse pas d’autres limitations.
Premièrement, le raisonnement du paragraphe "Caveats:" de Crescent n'a pas de sens. L'explication implique que coder "un groupe de if (erreur instance de MyError) else ..." est en quelque sorte fastidieux ou prolixe par rapport à plusieurs instructions catch. Plusieurs instances de plusieurs instances dans un même bloc catch sont aussi concises que plusieurs instructions catch: code propre et concis sans astuces. C’est un excellent moyen d’imiter la gestion des erreurs par Java, spécifique aux sous-types de jetables.
WRT "apparaît, la propriété de message de la sous-classe n'est pas définie", ce n'est pas le cas si vous utilisez une sous-classe Error correctement construite. Pour créer votre propre sous-classe ErrorX Error, copiez simplement le bloc de code commençant par "var MyError =", en remplaçant le mot "MyError" par "ErrorX". (Si vous souhaitez ajouter des méthodes personnalisées à votre sous-classe, suivez le texte exemple).
La limitation réelle et significative des sous-classes d’erreur JavaScript est que, pour les implémentations JavaScript ou les débogueurs qui suivent et génèrent un suivi de la pile et de l’emplacement d’instanciation, comme FireFox, un emplacement de votre propre implémentation de sous-classe Error classe, alors que si vous utilisiez une erreur directe, ce serait l'emplacement où vous avez exécuté "nouvelle erreur (...)"). Les utilisateurs de IE ne le remarqueraient probablement jamais, mais les utilisateurs de Fire Bug sur FF verront les valeurs de nom de fichier et de numéro de ligne inutiles signalées à côté de ces erreurs, et devront explorer la trace de la pile jusqu'à l'élément # 1 pour trouver le réel. lieu d'instanciation.
Que diriez-vous de cette solution?
Au lieu de lancer votre erreur personnalisée en utilisant:
throw new MyError("Oops!");
Vous devriez envelopper l'objet Error (un peu comme un décorateur):
throw new MyError(Error("Oops!"));
Cela garantit que tous les attributs sont corrects, tels que la pile, nomFichier, numéroDeLigne, et cetera.
Tout ce que vous avez à faire est alors de copier les attributs, ou de définir des getters pour eux.
function MyError(wrapped)
{
this.wrapped = wrapped;
this.wrapped.name = 'MyError';
}
function wrap(attr)
{
Object.defineProperty(MyError.prototype, attr, {
get: function()
{
return this.wrapped[attr];
}
});
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
wrap('name');
wrap('message');
wrap('stack');
wrap('fileName');
wrap('lineNumber');
wrap('columnNumber');
MyError.prototype.toString = function()
{
return this.wrapped.toString();
};
Ma solution est plus simple que les autres réponses fournies et ne présente pas d'inconvénient.
Il préserve la chaîne de prototypes d'Erreur et toutes ses propriétés sur Erreur sans avoir à les connaître spécifiquement. Il a été testé sous Chrome, Firefox, Node et IE11.
La seule limitation est une entrée supplémentaire en haut de la pile d'appels. Mais cela est facilement ignoré.
Voici un exemple avec deux paramètres personnalisés:
function CustomError(message, param1, param2) {
var err = new Error(message);
Object.setPrototypeOf(err, CustomError.prototype);
err.param1 = param1;
err.param2 = param2;
return err;
}
CustomError.prototype = Object.create(
Error.prototype,
{name: {value: 'CustomError', enumerable: false}}
);
Exemple d'utilisation:
try {
throw new CustomError('Something Unexpected Happened!', 1234, 'neat');
} catch (ex) {
console.log(ex.name); //CustomError
console.log(ex.message); //Something Unexpected Happened!
console.log(ex.param1); //1234
console.log(ex.param2); //neat
console.log(ex.stack); //stacktrace
console.log(ex instanceof Error); //true
console.log(ex instanceof CustomError); //true
}
Pour les environnements nécessitant un polyfil de setPrototypeOf:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
};
Dans l'exemple ci-dessus, Error.apply
(également Error.call
) ne fait rien pour moi (Firefox 3.6/Chrome 5). Une solution de contournement que j'utilise est la suivante:
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != 'undefined') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf('\n')+1);
}
else if (typeof(chrome) != 'undefined' || typeof(process) != 'undefined') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\n[^\n]*/,'');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';
Comme certains l'ont dit, c'est assez facile avec ES6:
class CustomError extends Error { }
J'ai donc essayé cela dans mon application (Angular, TypeScript) et cela n'a tout simplement pas fonctionné. Après un certain temps, j'ai constaté que le problème venait de TypeScript: O
Voir https://github.com/Microsoft/TypeScript/issues/13965
C'est très dérangeant parce que si vous le faites:
class CustomError extends Error {}
try {
throw new CustomError()
} catch(e) {
if (e instanceof CustomError) {
console.log('Custom error');
} else {
console.log('Basic error');
}
}
En noeud ou directement dans votre navigateur, il affichera: Custom error
Essayez d’exécuter cela avec TypeScript dans votre projet sur un terrain de jeu TypeScript, il affichera Basic error
...
La solution est la suivante:
class CustomError extends Error {
// we have to do the following because of: https://github.com/Microsoft/TypeScript/issues/13965
// otherwise we cannot use instanceof later to catch a given type
public __proto__: Error;
constructor(message?: string) {
const trueProto = new.target.prototype;
super(message);
this.__proto__ = trueProto;
}
}
Mes 2 centimes:
a) Parce que l’accès à la propriété Error.stack
(comme dans certaines réponses) a un impact important sur les performances.
b) Parce que ce n'est qu'une ligne.
c) Parce que la solution sur https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error ne semble pas conserver les informations sur la pile.
//MyError class constructor
function MyError(msg){
this.__proto__.__proto__ = Error.apply(null, arguments);
};
exemple d'utilisation
http://jsfiddle.net/luciotato/xXyeB/
this.__proto__.__proto__
est MyError.prototype.__proto__
, donc il définit le __proto__
FOR ALL INSTANCES de MyError sur une erreur spécifique nouvellement créée. Il conserve les propriétés et les méthodes de la classe MyError et place également les nouvelles propriétés Error (y compris .stack) dans la chaîne __proto__
.
Vous ne pouvez pas avoir plus d'une instance de MyError avec des informations utiles sur la pile.
N'utilisez pas cette solution si vous ne comprenez pas bien ce que fait this.__proto__.__proto__=
.
Je veux juste ajouter à ce que d'autres ont déjà déclaré:
Pour vous assurer que la classe d'erreur personnalisée apparaît correctement dans la trace de pile, vous devez définir la propriété name du prototype de la classe d'erreur personnalisée sur la propriété name de la classe d'erreur personnalisée . C'est ce que je veux dire:
CustomError.prototype = Error.prototype;
CustomError.prototype.name = 'CustomError';
Ainsi, l'exemple complet serait:
var CustomError = function(message) {
var err = new Error(message);
err.name = 'CustomError';
this.name = err.name;
this.message = err.message;
//check if there is a stack property supported in browser
if (err.stack) {
this.stack = err.stack;
}
//we should define how our toString function works as this will be used internally
//by the browser's stack trace generation function
this.toString = function() {
return this.name + ': ' + this.message;
};
};
CustomError.prototype = new Error();
CustomError.prototype.name = 'CustomError';
Quand tout est dit et fait, vous lancez votre nouvelle exception et elle ressemble à ceci (je l'ai essayé paresseusement dans les outils de développement de chrome):
CustomError: Stuff Happened. GASP!
at Error.CustomError (<anonymous>:3:19)
at <anonymous>:2:7
at Object.InjectedScript._evaluateOn (<anonymous>:603:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:562:52)
at Object.InjectedScript.evaluate (<anonymous>:481:21)
Dans Node comme d'autres l'ont déjà dit, c'est simple:
class DumbError extends Error {
constructor(foo = 'bar', ...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DumbError);
}
this.name = 'DumbError';
this.foo = foo;
this.date = new Date();
}
}
try {
let x = 3;
if (x < 10) {
throw new DumbError();
}
} catch (error) {
console.log(error);
}
Comme les exceptions JavaScript sont difficiles à sous-classer, je ne les sous-classent pas. Je viens de créer une nouvelle classe d'exception et d'utiliser une erreur à l'intérieur de celle-ci. Je modifie la propriété Error.name afin qu'elle ressemble à mon exception personnalisée sur la console:
var InvalidInputError = function(message) {
var error = new Error(message);
error.name = 'InvalidInputError';
return error;
};
La nouvelle exception ci-dessus peut être levée comme une erreur normale et fonctionnera comme prévu, par exemple:
throw new InvalidInputError("Input must be a string");
// Output: Uncaught InvalidInputError: Input must be a string
Avertissement: la trace de pile n'est pas parfaite, car elle vous mènera à l'endroit où la nouvelle erreur est créée et non à l'endroit où vous le lancez. Ce n'est pas un gros problème sur Chrome, car il vous fournit une trace de pile complète directement dans la console. Mais c'est plus problématique sous Firefox, par exemple.
Comme indiqué dans la réponse de Mohsen, dans ES6, il est possible d'étendre les erreurs à l'aide de classes. C'est beaucoup plus facile et leur comportement est plus cohérent avec les erreurs natives ... mais malheureusement, il n'est pas simple de l'utiliser dans le navigateur si vous devez prendre en charge les navigateurs antérieurs à l'ES6. Voir ci-dessous quelques notes sur la façon dont cela pourrait être mis en œuvre, mais dans l'intervalle, je suggère une approche relativement simple qui intègre certaines des meilleures suggestions d'autres réponses:
function CustomError(message) {
//This is for future compatibility with the ES6 version, which
//would display a similar message if invoked without the
//`new` operator.
if (!(this instanceof CustomError)) {
throw new TypeError("Constructor 'CustomError' cannot be invoked without 'new'");
}
this.message = message;
//Stack trace in V8
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
else this.stack = (new Error).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.name = 'CustomError';
Dans ES6, c'est aussi simple que:
class CustomError extends Error {}
... et vous pouvez détecter le support des classes ES6 avec try {eval('class X{}')
, mais vous obtiendrez une erreur de syntaxe si vous tentez d'inclure la version ES6 dans un script chargé par des navigateurs plus anciens. Ainsi, le seul moyen de prendre en charge tous les navigateurs serait de charger un script distinct de manière dynamique (par exemple via AJAX ou eval()
) pour les navigateurs prenant en charge ES6. Une complication supplémentaire est que eval()
n'est pas pris en charge dans tous les environnements (en raison des stratégies de sécurité du contenu), ce qui peut ou peut ne pas être une considération pour votre projet.
Donc pour l'instant, soit la première approche ci-dessus ou simplement l'utilisation de Error
directement sans essayer de l'étendre semble être ce qu'il y a de mieux pour le code devant supporter les navigateurs non-ES6.
Certaines personnes pourraient envisager une autre approche, qui consiste à utiliser Object.setPrototypeOf()
lorsqu'il est disponible pour créer un objet d'erreur qui est une instance de votre type d'erreur personnalisée mais qui ressemble davantage à une erreur native dans la console (grâce à Réponse de Ben pour la recommandation). Voici mon point de vue sur cette approche: https://Gist.github.com/mbrowne/fe45db61cea7858d11be933a998926a8 . Mais étant donné qu’un jour nous pourrons utiliser uniquement ES6, personnellement, je ne suis pas sûr que la complexité de cette approche en vaille la peine.
Pour ce faire, vous devez renvoyer le résultat de apply du constructeur et définir le prototype de la manière javascript compliquée habituelle:
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 ...>
Les seuls problèmes avec cette façon de le faire à ce stade (je l'ai un peu réitéré) sont les suivants:
stack
et message
ne sont pas incluses dans MyError
et Le premier problème pourrait être résolu en parcourant toutes les propriétés d'erreur non énumérables en utilisant le truc utilisé dans cette réponse: Est-il possible d'obtenir les noms de propriété hérités non énumérables d'un objet? , mais ceci n'est pas supporté par ie <9. Le deuxième problème pourrait être résolu en déchirant cette ligne dans la trace de la pile, mais je ne sais pas comment le faire en toute sécurité (peut-être simplement en supprimant la deuxième ligne de e.stack.toString () ??).
Ceci est basé sur la réponse de George Bailey , mais étend et simplifie l'idée originale. Il est écrit en CoffeeScript, mais il est facile à convertir en JavaScript. L'idée est d'étendre l'erreur personnalisée de Bailey avec un décorateur qui l'enveloppe, vous permettant de créer facilement de nouvelles erreurs personnalisées.
Note: Cela ne fonctionnera que dans V8. Error.captureStackTrace
n'est pas pris en charge dans d'autres environnements.
Le décorateur prend un nom pour le type d'erreur et renvoie une fonction qui prend un message d'erreur et entoure le nom de l'erreur.
CoreError = (@message) ->
@constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace @, @constructor
@name = @constructor.name
BaseError = (type) ->
(message) -> new CoreError "#{ type }Error: #{ message }"
Maintenant, il est simple de créer de nouveaux types d'erreur.
StorageError = BaseError "Storage"
SignatureError = BaseError "Signature"
Pour le plaisir, vous pouvez maintenant définir une fonction qui lance une SignatureError
si elle est appelée avec trop d'arguments.
f = -> throw SignatureError "too many args" if arguments.length
Cela a été assez bien testé et semble fonctionner parfaitement sur V8, en maintenant le traçage, la position etc.
Remarque: L'utilisation de new
est facultative lors de la création d'une erreur personnalisée.
L'extrait montre tout.
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)
}
}
Je prendrais un pas en arrière et examinerais pourquoi tu veux faire ça? Je pense que le but est de traiter différentes erreurs différemment.
Par exemple, en Python, vous pouvez limiter l’instruction catch à catch MyValidationError
, et vous souhaitez peut-être faire quelque chose de similaire en javascript.
catch (MyValidationError e) {
....
}
Vous ne pouvez pas faire cela en javascript. Il n'y aura qu'un seul bloc captif. Vous êtes censé utiliser une instruction if sur l'erreur pour déterminer son type.
catch(e) {
if(isMyValidationError(e)) {
...
} else {
// maybe rethrow?
throw e;
}
}
Je pense que je jetterais plutôt un objet brut avec un type, un message et toute autre propriété que vous jugerez utile.
throw { type: "validation", message: "Invalid timestamp" }
Et quand vous attrapez l'erreur:
catch(e) {
if(e.type === "validation") {
// handle error
}
// re-throw, or whatever else
}