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?

202
demandé sur Manki 2009-01-21 10:40:32

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;} 
}; 
211
répondu jon077 2018-07-04 16:02:48

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");
}
76
répondu Sergey Ilinsky 2013-01-23 14:16:45

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!
75
répondu asselin 2014-12-31 17:37:29

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.

36
répondu Rob Kennedy 2009-01-21 08:22:04
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();
}
25
répondu Morgan ARR Allen 2011-01-18 20:54:49

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.

11
répondu disfated 2012-01-12 03:38:32

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();
11
répondu Matthias 2012-08-13 12:25:38

en bref:

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:

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
7
répondu JBE 2017-05-23 11:47:26

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.

5
répondu Xn0vv3r 2012-09-07 19:20:47

ES6

avec la nouvelle classe et extend keywords il est maintenant beaucoup plus facile:

class CustomError extends Error {
  constructor(message) {
    super(message);
    //something
  }
}
2
répondu Brunno 2017-11-29 17:22:28

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;
    }
}
1
répondu Mr Tsjolder 2017-05-23 12:02:47
//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.

1
répondu mateen 2017-08-21 10:53:47

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?

0
répondu Peter Tseng 2017-05-23 12:26:36