Tôi có thể xác định loại tùy chỉnh cho các ngoại lệ do người dùng xác định trong JavaScript không? Nếu vậy, tôi sẽ làm thế nào?
Tôi có thể xác định loại tùy chỉnh cho các ngoại lệ do người dùng xác định trong JavaScript không? Nếu vậy, tôi sẽ làm thế nào?
Câu trả lời:
Từ 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; } }
⦃⦄ hoặc catch (e) { switch (e.constructor) { case TypeError: …; break; default: throw e; }
⦃⦄.
Bạn nên tạo một ngoại lệ tùy chỉnh mà nguyên mẫu kế thừa từ Lỗi. Ví dụ:
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;
Về cơ bản, đây là phiên bản đơn giản hóa của những gì bị biến dạng được đăng ở trên với sự cải tiến mà dấu vết ngăn xếp hoạt động trên Firefox và các trình duyệt khác. Nó đáp ứng các bài kiểm tra tương tự mà ông đã đăng:
Sử dụng:
throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");
Và nó sẽ hành xử được mong đợi:
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!
Bạn có thể thực hiện các ngoại lệ của riêng bạn và xử lý chúng chẳng hạn như ở đây:
// 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");
}
}
Có một cú pháp khác để bắt ngoại lệ được gõ, mặc dù điều này sẽ không hoạt động trong mọi trình duyệt (ví dụ không phải trong 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");
}
Đúng. Bạn có thể ném bất cứ thứ gì bạn muốn: số nguyên, chuỗi, đối tượng, bất cứ thứ gì. Nếu bạn muốn ném một đối tượng, thì chỉ cần tạo một đối tượng mới, giống như bạn sẽ tạo một đối tượng trong các trường hợp khác, và sau đó ném nó. Tài liệu tham khảo Javascript của Mozilla có một số ví dụ.
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error;
Điều này cho phép sử dụng như ..
try {
something();
} catch(e) {
if(e instanceof MyError)
doSomethingElse();
else if(e instanceof Error)
andNowForSomethingCompletelyDifferent();
}
e instanceof Error
sẽ là sai.
e instanceof MyError
sẽ là sự thật, else if(e instanceof Error)
tuyên bố sẽ không bao giờ được đánh giá.
else if(e instanceof Error)
sẽ là bắt cuối cùng. Có khả năng theo sau là một đơn giản else
(mà tôi không bao gồm). Sắp xếp giống như default:
trong một câu lệnh chuyển đổi nhưng cho lỗi.
Nói ngắn gọn:
Nếu bạn đang sử dụng ES6 mà không có bộ chuyển đổi :
class CustomError extends Error { /* ... */}
Xem Lỗi mở rộng trong Javascript với cú pháp ES6 để biết cách thực hành tốt nhất hiện tại
Nếu bạn đang sử dụng bộ chuyển mã Babel :
Tùy chọn 1: sử dụng babel-plugin-Transform-buildin-extend
Tùy chọn 2: tự làm (lấy cảm hứng từ cùng một thư viện)
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);
Nếu bạn đang sử dụng ES5 thuần túy :
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;
}
Thay thế: sử dụng khung Classtrophobic
Giải trình:
Tại sao việc mở rộng lớp Error bằng ES6 và Babel là một vấn đề?
Bởi vì một phiên bản của CustomError không còn được công nhận như vậy nữa.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
Trong thực tế, từ các tài liệu chính thức của Babel, bạn không thể mở rộng bất kỳ được xây dựng trong các lớp học JavaScript như Date
, Array
, DOM
hoặc Error
.
Vấn đề được mô tả ở đây:
Những câu trả lời SO khác thì sao?
Tất cả các câu trả lời đã khắc phục sự cố instanceof
nhưng bạn mất lỗi thông thường console.log
:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5"}
Trong khi sử dụng phương pháp được đề cập ở trên, không chỉ bạn khắc phục sự cố instanceof
mà bạn còn giữ lỗi thường xuyên console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
Đây là cách bạn có thể tạo các lỗi tùy chỉnh hoàn toàn giống với Error
hành vi của người bản xứ . Kỹ thuật này chỉ hoạt động trong Chrome và Node.js cho bây giờ. Tôi cũng không khuyên bạn nên sử dụng nó nếu bạn không hiểu nó làm gì.
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;
}
})();
Như một reasult chúng tôi nhận được
/**
* 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)
Sau đó, bạn có thể sử dụng nó như thế này:
var NotImplementedError = Error.createCustromConstructor('NotImplementedError');
Và sử dụng NotImplementedError
như bạn muốn Error
:
throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');
Và nó sẽ hành xử được mong đợi:
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!
Lưu ý, điều đó error.stack
hoạt động hoàn toàn chính xác và sẽ không bao gồm NotImplementedError
cuộc gọi của nhà xây dựng (nhờ v8's Error.captureStackTrace()
).
Ghi chú. Có xấu xí eval()
. Lý do duy nhất nó được sử dụng là để có được chính xác err.constructor.name
. Nếu bạn không cần nó, bạn có thể đơn giản hóa mọi thứ.
Error.apply(self, arguments)
được chỉ định không hoạt động . Tôi đề nghị sao chép theo dõi ngăn xếp thay vì tương thích trình duyệt chéo.
Tôi thường sử dụng một cách tiếp cận với thừa kế nguyên mẫu. Ghi đè toString()
cung cấp cho bạn lợi thế là các công cụ như Fireorms sẽ ghi lại thông tin thực tế thay vì [object Object]
vào bảng điều khiển cho các trường hợp ngoại lệ chưa được phát hiện.
Sử dụng instanceof
để xác định loại ngoại lệ.
// 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();
Sử dụng câu lệnh ném .
JavaScript không quan tâm loại ngoại lệ là gì (như Java làm). JavaScript chỉ cần thông báo, có một ngoại lệ và khi bạn bắt được nó, bạn có thể "xem" ngoại lệ "nói gì".
Nếu bạn có các loại ngoại lệ khác nhau mà bạn phải ném, tôi khuyên bạn nên sử dụng các biến có chứa chuỗi / đối tượng của ngoại lệ tức là thông báo. Trường hợp bạn cần sử dụng "throw myException" và trong phần bắt, hãy so sánh ngoại lệ bị bắt với myException.
Xem ví dụ này trong MDN.
Nếu bạn cần xác định nhiều lỗi (kiểm tra mã ở đây !):
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;
Mã được sao chép chủ yếu từ: Cách tốt để mở rộng Lỗi trong JavaScript là gì?
Một thay thế cho câu trả lời của asselin để sử dụng với các lớp 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;
}
}
Bây giờ chúng ta đặt thêm lý do hoặc bất kỳ thuộc tính nào chúng ta muốn vào đối tượng lỗi và truy xuất nó. Bằng cách làm cho lỗi hợp lý hơn.