Özel istisna türü


224

JavaScript'te kullanıcı tanımlı özel durumlar için özel türler tanımlayabilir miyim? Öyleyse, nasıl yaparım?


3
Dikkat. 10 Dakikadaki JavaScript'e göre, kutusuz bir değer atarsanız yığın izlemesi alamazsınız.
Janus Troelsen

exceptionsjs.com , özel istisnalar oluşturma olanağı sağlar ve varsayılan olarak ArgumentException ve NotImplemented dahil olmak üzere bazı eksik istisnaları sağlar.
Steven Wexler

Yanıtlar:


232

Gönderen 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;} 
}; 

7
@ b.long "JavaScript: İyi Parçalar" (harika bir kitap IMO). Bu Google Kitaplar önizlemesi şu bölümü gösterir: books.google.com/books?id=PXa2bby0oQ0C&pg=PA32&lpg=PA32
orip

11
Bir toString yöntemi eklemek, javascript konsolunda güzel görünmesini sağlayacaktır. olmadan şöyle görünür: toString ile Uncaught # <Object> şöyle görünür: Uncaught System Error: Hata tespit edildi. Lütfen sistem yöneticisine başvurun.
JDC

11
Bu, Hata'dan devralmadığınız sürece izleri biriktirmenize izin vermez
Luke H

Yalnızca bu özel hatayla çalışmak için bir catch bloğunda nasıl filtreleme yapabilirsiniz?
Overdrivr

@overdrivr catch (e) { if (e instanceof TypeError) { … } else { throw e; } }⦃⦄ veya ⦃⦄ gibi bir şey catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }.
sam boosalis

92

Prototipsel olarak Hata'dan devralan özel bir istisna oluşturmalısınız. Örneğin:

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;

Bu temelde ne basitleştirilmiş bir versiyonudur disfated yığın izleri Firefox ve diğer tarayıcılarda çalışmasını geliştirme ile yukarıda yayınlanmıştır. Gönderdiği testlerin aynısını karşılar:

Kullanımı:

throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");

Ve davranması bekleniyor:

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!

80

Kendi istisnalarınızı ve bunların işlenmesini örneğin aşağıdaki gibi uygulayabilirsiniz:

// 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");
    }
}

Yazılan bir istisnayı yakalamak için başka bir sözdizimi vardır, ancak bu her tarayıcıda çalışmaz (örneğin IE'de):

// 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");
}

2
MSN web sitesi koşul yakalamalarla ilgili şu uyarıyı taşır: Standart dışı Bu özellik standart değildir ve standartlar üzerinde değildir. Web'e bakan üretim sitelerinde kullanmayın: her kullanıcı için çalışmaz. Uygulamalar arasında büyük uyumsuzluklar olabilir ve gelecekte davranışlar değişebilir.
Lawrence Dol

40

Evet. İstediğiniz her şeyi atabilirsiniz: tamsayılar, dizeler, nesneler, ne olursa olsun. Bir nesneyi fırlatmak istiyorsanız, tıpkı diğer koşullar altında bir nesneyi yaratacağınız gibi yeni bir nesne oluşturun ve atın. Mozilla'nın Javascript referansının birkaç örneği vardır.


26
function MyError(message) {
 this.message = message;
}

MyError.prototype = new Error;

Bu gibi kullanım sağlar ..

try {
  something();
 } catch(e) {
  if(e instanceof MyError)
   doSomethingElse();
  else if(e instanceof Error)
   andNowForSomethingCompletelyDifferent();
}

Bu kısa örnek, Hata'nın prototipini devralmasanız bile tam olarak aynı şekilde çalışmaz mı? Bu örnekte bunun size ne kazandığı açık değil.
EleventyOne

1
Hayır, e instanceof Erroryanlış olur.
Morgan ARR Allen

Aslında. Ancak e instanceof MyErrordoğru olacağından, else if(e instanceof Error)ifade asla değerlendirilmez.
EleventyOne

Doğru, bu sadece bu deneme / yakalama tarzının nasıl çalışacağının bir örneğidir. else if(e instanceof Error)Son yakalama nerede olurdu. Muhtemelen bir basit else(ki ben dahil etmedi) izledi . Sıralama benzeri default:bir switch deyiminde ama hatalar için.
Morgan ARR Allen

15

Kısacası:

Seçenek 1: Babel-Plugin-Transform-Builtin-Extend kullanın

2.Seçenek: Kendiniz yapın (aynı kütüphaneden esinlenerek)

    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);
  • Saf ES5 kullanıyorsanız :

    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;
    }
  • Alternatif: Classtrophobic framework kullanın

Açıklama:

Error sınıfını ES6 ve Babel kullanarak genişletmek neden bir sorundur?

Çünkü CustomError örneği artık bu şekilde tanınmıyor.

class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false

Aslında, Babil resmi belgelerinden, sen herhangi yerleşik JavaScript sınıfları uzatamaz gibi Date, Array, DOMveya Error.

Sorun burada açıklanmaktadır:

Diğer SO cevapları ne olacak?

Verilen tüm cevaplar sorunu düzeltir, instanceofancak normal hatayı kaybedersiniz console.log:

console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵    at CustomError (<anonymous>:4:19)↵    at <anonymous>:1:5"}

Yukarıda belirtilen yöntemi kullanırken, yalnızca instanceofsorunu düzeltmekle kalmaz, aynı zamanda normal hatayı da tutarsınız console.log:

console.log(new CustomError('test'));
// output:
// Error: test
//     at CustomError (<anonymous>:2:32)
//     at <anonymous>:1:5

11

Yerel Errordavranışla tamamen aynı özel hataları nasıl oluşturabileceğiniz aşağıda açıklanmıştır . Bu teknik şimdilik sadece Chrome ve node.js'de çalışıyor . Ne yaptığını anlamıyorsanız da kullanmanız tavsiye edilmez.

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;
    }

})();

Bir reasürans olarak

/**
 * 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)

O zaman bu şekilde kullanabilirsiniz:

var NotImplementedError = Error.createCustromConstructor('NotImplementedError');

Ve NotImplementedErroristediğiniz gibi kullanın Error:

throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');

Ve davranması bekleniyor:

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!

Bunun error.stackmutlak doğru çalıştığını ve NotImplementedErroryapıcı çağrısı içermediğini unutmayın (v8'ler sayesinde Error.captureStackTrace()).

Not. Çirkin var eval(). Kullanılmasının tek nedeni düzeltmektir err.constructor.name. İhtiyacınız yoksa, her şeyi biraz basitleştirebilirsiniz.


2
Error.apply(self, arguments)olduğu işe belirtilmemiş . Çapraz tarayıcı uyumlu olan yığın izlemesini kopyalamanızı öneririm .
Kornel

11

Genellikle prototip kalıtımla ilgili bir yaklaşım kullanıyorum. Geçersiz kılma toString()size Firebug gibi araçların gerçek bilgileri kaydetme avantajı sağlar[object Object] yakalanmamış istisnalar için konsol kaydetme .

instanceofİstisna türünü belirlemek için kullanın .

main.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();

8

ES6

Yeni sınıf ve anahtar kelimeleri genişletmek artık çok daha kolay:

class CustomError extends Error {
  constructor(message) {
    super(message);
    //something
  }
}

7

Throw ifadesini kullanın .

JavaScript, istisna türünün ne olduğunu umursamaz (Java'nın yaptığı gibi). JavaScript sadece fark eder, bir istisna vardır ve onu yakaladığınızda, istisnanın ne dediğine "bakabilirsiniz".

Eğer atmanız gereken farklı istisna türleri varsa, istisna yani mesajın dizesini / nesnesini içeren değişkenleri kullanmanızı öneririm. İhtiyacınız olan yerde "myException'ı kullanın" ve yakalamada, yakalanan istisnayı myException ile karşılaştırın.


1

Bu örneğe bakınMDN'deki .

Birden fazla Hata tanımlamanız gerekiyorsa (kodu buradan test edin !):

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;

Kod çoğunlukla kopyalanan: JavaScript'te Hata'yı genişletmenin iyi bir yolu nedir?


1

Verilen yanıta alternatif Asselin'e ES2015 sınıfları ile kullanmak için

class InvalidArgumentException extends Error {
    constructor(message) {
        super();
        Error.captureStackTrace(this, this.constructor);
        this.name = "InvalidArgumentException";
        this.message = message;
    }
}

1
//create error object
var error = new Object();
error.reason="some reason!";

//business function
function exception(){
    try{
        throw error;
    }catch(err){
        err.reason;
    }
}

Şimdi hata nesnesine neden veya ne tür özellikler eklemek istediğimizi ayarlayıp geri alıyoruz. Hatayı daha makul hale getirerek.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.