JavaScript'te kullanıcı tanımlı özel durumlar için özel türler tanımlayabilir miyim? Öyleyse, nasıl yaparım?
JavaScript'te kullanıcı tanımlı özel durumlar için özel türler tanımlayabilir miyim? Öyleyse, nasıl yaparım?
Yanıtlar:
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;}
};
catch (e) { if (e instanceof TypeError) { … } else { throw e; } }
⦃⦄ veya ⦃⦄ gibi bir şey catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }
.
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!
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");
}
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.
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();
}
e instanceof Error
yanlış olur.
e instanceof MyError
doğru olacağından, else if(e instanceof Error)
ifade asla değerlendirilmez.
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.
Kısacası:
Transferi olmayan ES6 kullanıyorsanız :
class CustomError extends Error { /* ... */}
En iyi geçerli uygulama nedir? İçin Javascript'te ES6 sözdizimi ile hatayı genişletme konusuna bakın.
Babel transpiler kullanıyorsanız :
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
, DOM
veya Error
.
Sorun burada açıklanmaktadır:
Diğer SO cevapları ne olacak?
Verilen tüm cevaplar sorunu düzeltir, instanceof
ancak 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 instanceof
sorunu 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
Yerel Error
davranış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 NotImplementedError
istediğ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.stack
mutlak doğru çalıştığını ve NotImplementedError
yapı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.
Error.apply(self, arguments)
olduğu işe belirtilmemiş . Çapraz tarayıcı uyumlu olan yığın izlemesini kopyalamanızı öneririm .
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 .
// 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();
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.
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?
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;
}
}
//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.