Bisakah saya menentukan jenis khusus untuk pengecualian yang ditentukan pengguna dalam JavaScript? Jika demikian, bagaimana saya melakukannya?
Bisakah saya menentukan jenis khusus untuk pengecualian yang ditentukan pengguna dalam JavaScript? Jika demikian, bagaimana saya melakukannya?
Jawaban:
Dari 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; } }⦃⦄ atau catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }⦃⦄.
Anda harus membuat pengecualian khusus yang secara bawaan mewarisi dari Kesalahan. Sebagai contoh:
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;
Ini pada dasarnya adalah versi yang disederhanakan dari apa yang disayangkan diposting di atas dengan perangkat tambahan yang berfungsi melacak jejak pada Firefox dan browser lainnya. Itu memenuhi tes yang sama yang dia posting:
Pemakaian:
throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");
Dan itu akan berperilaku diharapkan:
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!
Anda dapat menerapkan pengecualian Anda sendiri dan penanganannya misalnya seperti di sini:
// 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");
}
}
Ada sintaks lain untuk menangkap pengecualian yang diketik, meskipun ini tidak akan berfungsi di setiap browser (misalnya tidak di 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");
}
Iya. Anda dapat melempar apa pun yang Anda inginkan: bilangan bulat, string, objek, apa pun. Jika Anda ingin melempar objek, maka cukup buat objek baru, sama seperti Anda akan membuatnya dalam keadaan lain, lalu melemparkannya. Referensi Javascript Mozilla memiliki beberapa contoh.
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error;
Ini memungkinkan untuk penggunaan seperti ..
try {
something();
} catch(e) {
if(e instanceof MyError)
doSomethingElse();
else if(e instanceof Error)
andNowForSomethingCompletelyDifferent();
}
e instanceof Erroritu salah.
e instanceof MyErroritu benar, else if(e instanceof Error)pernyataan itu tidak akan pernah dievaluasi.
else if(e instanceof Error)akan menjadi tangkapan terakhir. Kemungkinan diikuti oleh yang sederhana else(yang tidak saya sertakan). Agak seperti default:dalam pernyataan switch tetapi untuk kesalahan.
Pendeknya:
Jika Anda menggunakan ES6 tanpa transpiler :
class CustomError extends Error { /* ... */}
Lihat Memperluas Kesalahan dalam Javascript dengan sintaksis ES6 untuk mengetahui praktik terbaik saat ini
Jika Anda menggunakan Babel transpiler :
Opsi 1: gunakan babel-plugin-transform-builtin-extended
Opsi 2: lakukan sendiri (terinspirasi dari perpustakaan yang sama)
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);
Jika Anda menggunakan ES5 murni :
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: gunakan kerangka kerja Classtrophobic
Penjelasan:
Mengapa memperluas kelas Kesalahan menggunakan ES6 dan Babel merupakan masalah?
Karena turunan CustomError tidak lagi dikenali.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
Bahkan, dari dokumentasi resmi Babel, Anda tidak dapat memperpanjang built-in kelas JavaScript seperti Date, Array, DOMatau Error.
Masalahnya dijelaskan di sini:
Bagaimana dengan jawaban SO lainnya?
Semua jawaban yang diberikan memperbaiki instanceofmasalah tetapi Anda kehilangan kesalahan reguler console.log:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5"}
Sedangkan menggunakan metode yang disebutkan di atas, tidak hanya Anda memperbaiki instanceofmasalah tetapi Anda juga menyimpan kesalahan rutin console.log:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
Di sini adalah bagaimana Anda dapat membuat kesalahan khusus dengan sepenuhnya identik dengan Errorperilaku asli. Teknik ini hanya berfungsi di Chrome dan node.js untuk saat ini. Saya juga tidak akan merekomendasikan untuk menggunakannya jika Anda tidak mengerti apa fungsinya.
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;
}
})();
Sebagai hasil kita dapatkan
/**
* 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)
Maka Anda dapat menggunakannya seperti ini:
var NotImplementedError = Error.createCustromConstructor('NotImplementedError');
Dan gunakan NotImplementedErrorseperti yang Anda inginkan Error:
throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');
Dan itu akan berperilaku diharapkan:
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!
Catatan, itu error.stackberfungsi absolut dengan benar dan tidak akan menyertakan NotImplementedErrorpanggilan konstruktor (terima kasih kepada v8 Error.captureStackTrace()).
Catatan. Ada yang jelek eval(). Satu-satunya alasan digunakan adalah untuk mendapatkan yang benar err.constructor.name. Jika Anda tidak membutuhkannya, Anda dapat sedikit menyederhanakan semuanya.
Error.apply(self, arguments)adalah ditentukan tidak bekerja . Saya sarankan untuk menyalin jejak stack yang kompatibel dengan cross-browser.
Saya sering menggunakan pendekatan dengan pewarisan prototypal. Overriding toString()memberi Anda keuntungan bahwa alat-alat seperti Firebug akan mencatat informasi aktual alih-alih [object Object]ke konsol untuk pengecualian yang tidak tertangkap.
Gunakan instanceofuntuk menentukan jenis pengecualian.
// 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();
Gunakan pernyataan melempar .
JavaScript tidak peduli apa jenis pengecualiannya (seperti halnya Java). JavaScript hanya pemberitahuan, ada pengecualian dan ketika Anda menangkapnya, Anda bisa "melihat" apa yang dikatakan "pengecualian".
Jika Anda memiliki berbagai jenis pengecualian yang harus Anda buang, saya sarankan untuk menggunakan variabel yang berisi string / objek dari pesan pengecualian yaitu. Di mana Anda membutuhkannya, gunakan "throw myException" dan dalam tangkapan, bandingkan pengecualian yang tertangkap dengan myException.
Lihat contoh ini di MDN.
Jika Anda perlu mendefinisikan beberapa Kesalahan (uji kodenya di sini !):
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;
Kode sebagian besar disalin dari: Apa cara yang baik untuk memperpanjang Kesalahan dalam JavaScript?
Alternatif jawaban asselin untuk digunakan dengan kelas 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;
}
}
Sekarang kita atur menambahkan alasan atau properti apa pun yang kita inginkan ke objek kesalahan dan mengambilnya. Dengan membuat kesalahan lebih masuk akal.