ฉันสามารถกำหนดประเภทที่กำหนดเองสำหรับข้อยกเว้นที่ผู้ใช้กำหนดใน JavaScript ได้หรือไม่ ถ้าเป็นเช่นนั้นฉันจะทำอย่างไร
ฉันสามารถกำหนดประเภทที่กำหนดเองสำหรับข้อยกเว้นที่ผู้ใช้กำหนดใน JavaScript ได้หรือไม่ ถ้าเป็นเช่นนั้นฉันจะทำอย่างไร
คำตอบ:
จาก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; } }
⦃⦄หรือcatch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }
⦃⦄
คุณควรสร้างข้อยกเว้นแบบกำหนดเองที่ต้นแบบสืบทอดมาจากข้อผิดพลาด ตัวอย่างเช่น:
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;
นี่เป็นเวอร์ชั่นที่เรียบง่ายของสิ่งที่ถูกโพสต์ไว้ข้างต้นด้วยการปรับปรุงที่สแต็กติดตามทำงานบน Firefox และเบราว์เซอร์อื่น ๆ มันเป็นไปตามการทดสอบเดียวกันกับที่เขาโพสต์:
การใช้งาน:
throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");
และมันจะทำงานตามที่คาดไว้:
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!
คุณสามารถใช้ข้อยกเว้นของคุณเองและจัดการตัวอย่างเช่นที่นี่:
// 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");
}
}
มีอีกซินแทกซ์สำหรับจับข้อยกเว้นที่พิมพ์แม้ว่าจะไม่ทำงานในทุกเบราว์เซอร์ (ตัวอย่างเช่นไม่ได้อยู่ใน 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");
}
ใช่. คุณสามารถโยนสิ่งที่คุณต้องการ: จำนวนเต็มสตริงวัตถุอะไรก็ได้ หากคุณต้องการที่จะโยนวัตถุเพียงแค่สร้างวัตถุใหม่เช่นเดียวกับที่คุณจะสร้างวัตถุภายใต้สถานการณ์อื่นแล้วโยนมัน การอ้างอิง Javascript ของ Mozillaมีหลายตัวอย่าง
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error;
นี้ช่วยให้การใช้งานเช่น ..
try {
something();
} catch(e) {
if(e instanceof MyError)
doSomethingElse();
else if(e instanceof Error)
andNowForSomethingCompletelyDifferent();
}
e instanceof Error
จะเป็นเท็จ
e instanceof MyError
จะเป็นจริงelse if(e instanceof Error)
ข้อความจะไม่ถูกประเมิน
else if(e instanceof Error)
จะจับสุดท้าย น่าจะตามมาด้วยความเรียบง่ายelse
(ซึ่งฉันไม่ได้รวม) เรียงจากชอบdefault:
ในคำสั่งเปลี่ยน แต่สำหรับข้อผิดพลาด
ในระยะสั้น:
หากคุณกำลังใช้ ES6 โดยไม่มีทรานสปอนเดอร์ :
class CustomError extends Error { /* ... */}
ดูการขยายข้อผิดพลาดใน Javascript ที่มีไวยากรณ์ ES6สำหรับแนวปฏิบัติที่เหมาะสมที่สุดในปัจจุบันคืออะไร
หากคุณกำลังใช้Babel transpiler :
ตัวเลือก 1: ใช้babel-plugin-transform-builtin-expand
ตัวเลือกที่ 2: ทำด้วยตัวเอง (แรงบันดาลใจจากห้องสมุดเดียวกัน)
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);
หากคุณใช้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;
}
ทางเลือก: ใช้Classtrophobic framework
คำอธิบาย:
เหตุใดการขยายคลาสข้อผิดพลาดโดยใช้ ES6 และ Babel จึงเป็นปัญหา
เนื่องจากอินสแตนซ์ของ CustomError ไม่ได้รับการยอมรับเช่นนี้อีกต่อไป
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
ในความเป็นจริงจากเอกสารอย่างเป็นทางการของบาเบลที่คุณไม่สามารถขยายตัวใด ๆ ในชั้นเรียนของ JavaScriptเช่นDate
, Array
, หรือDOM
Error
ปัญหาอธิบายไว้ที่นี่:
แล้วคำตอบ SO อื่น ๆ ล่ะ?
คำตอบที่ให้ทั้งหมดแก้ไขinstanceof
ปัญหา แต่คุณสูญเสียข้อผิดพลาดปกติconsole.log
:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5"}
ในขณะที่ใช้วิธีการดังกล่าวข้างต้นไม่เพียง แต่คุณแก้ไขinstanceof
ปัญหา แต่คุณยังเก็บข้อผิดพลาดปกติconsole.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
นี่คือวิธีที่คุณสามารถสร้างข้อผิดพลาดที่กำหนดเองกับสมบูรณ์เหมือนกับพื้นเมืองError
พฤติกรรม เทคนิคนี้ใช้ได้เฉพาะใน Chrome และ node.jsเท่านั้น ฉันจะไม่แนะนำให้ใช้ถ้าคุณไม่เข้าใจว่ามันทำอะไร
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;
}
})();
ในฐานะที่เป็น reasult เราได้รับ
/**
* 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)
จากนั้นคุณสามารถใช้สิ่งนี้:
var NotImplementedError = Error.createCustromConstructor('NotImplementedError');
และใช้NotImplementedError
ตามที่คุณต้องการError
:
throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');
และมันจะทำงานตามที่คาดไว้:
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!
โปรดทราบว่าใช้error.stack
งานได้อย่างถูกต้องและไม่รวมNotImplementedError
การโทรคอนสตรัค (ขอบคุณ v8 ของError.captureStackTrace()
)
บันทึก. eval()
นอกจากนี้ที่น่าเกลียด err.constructor.name
เหตุผลเดียวที่มันถูกนำมาใช้คือการได้รับที่ถูกต้อง หากคุณไม่ต้องการคุณสามารถทำให้ทุกอย่างง่ายขึ้นเล็กน้อย
Error.apply(self, arguments)
จะระบุไม่ได้ไปทำงาน ฉันขอแนะนำให้คัดลอกการติดตามสแต็กแทนซึ่งเข้ากันได้ข้ามเบราว์เซอร์
ฉันมักจะใช้วิธีการที่มีมรดกต้นแบบ การเอาชนะtoString()
จะช่วยให้คุณได้เปรียบที่เครื่องมือเช่น Firebug จะบันทึกข้อมูลจริงแทนที่จะ[object Object]
ไปยังคอนโซลสำหรับข้อยกเว้นที่ไม่ได้ตรวจสอบ
ใช้instanceof
เพื่อกำหนดประเภทของข้อยกเว้น
// 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();
ES6
ด้วยคลาสใหม่และขยายคำหลักตอนนี้ง่ายขึ้นมาก:
class CustomError extends Error {
constructor(message) {
super(message);
//something
}
}
ใช้คำสั่งThrow
JavaScript ไม่สนใจประเภทของข้อยกเว้น (เช่น Java) JavaScript เพิ่งสังเกตเห็นมีข้อยกเว้นและเมื่อคุณจับคุณสามารถ "ดู" สิ่งที่ยกเว้น "พูดว่า"
หากคุณมีประเภทข้อยกเว้นต่าง ๆ ที่คุณต้องโยนฉันขอแนะนำให้ใช้ตัวแปรที่มีสตริง / วัตถุของข้อยกเว้นเช่นข้อความ ที่ใดที่คุณต้องการให้ใช้ "throw myException" และใน catch ให้เปรียบเทียบข้อยกเว้น catch กับ myException
ดูตัวอย่างนี้ใน MDN
หากคุณต้องการกำหนดข้อผิดพลาดหลายรายการ (ทดสอบรหัสที่นี่ !):
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;
รหัสส่วนใหญ่จะถูกคัดลอกมาจาก: วิธีที่ดีในการขยายข้อผิดพลาดใน JavaScript คืออะไร?
ทางเลือกสำหรับคำตอบของasselinสำหรับใช้กับคลาส 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;
}
}
ตอนนี้เราตั้งค่าเพิ่มเหตุผลหรือคุณสมบัติใด ๆ ที่เราต้องการวัตถุข้อผิดพลาดและดึงมัน โดยทำให้เกิดข้อผิดพลาดที่สมเหตุสมผลมากขึ้น