总所周知,当系统运行出现错误的时候,就会抛出一个Error,那么这个Error是什么?它是怎么来的?它又是怎么被抛出的?它又是怎么被捕获的?这些问题,我们一起来探讨一下。
1. Error
Error是一个对象,它是浏览器提供的一个内置对象,它的实例属性主要有:
name:错误的名称,比如TypeError,ReferenceError等
message:错误的描述信息
cause:错误的原因
stack:错误的堆栈信息,非标准属性
fileName:错误发生的文件名,非标准属性,Mozilla提供
lineNumber:错误发生的行号,非标准属性,Mozilla提供
columnNumber:错误发生的列号,非标准属性,Mozilla提供
line:错误发生的行的内容,非标准属性,Mozilla提供
静态属性:
Error.captureStackTrace:捕获错误的堆栈信息,非标准属性,V8提供
Error.stackTraceLimit:设置错误堆栈信息的最大长度,非标准属性,V8提供
静态方法:
Error.captureStackTrace():捕获错误的堆栈信息,非标准方法,V8提供
Error.prepareStackTrace():格式化错误堆栈
Error.stackTraceLimit:设置错误堆栈信息的最大长度,非标准方法,V8提供
实例方法:
error.toString():返回错误的字符串表示,覆盖了Object.prototype.toString()方法
2. Error的创建
Error对象是通过new关键字来创建的,它的构造函数有三种形式:
new Error(message)
new Error(message, { cause })
new Error(message, fileName, lineNumber)
其中,message是错误的描述信息,cause是错误的原因,它们都是可选的。
目前只有message和cause两个参数是确定的;
name属性是不确定的,它的值取决于错误的类型,比如TypeError,ReferenceError等;
stack属性也是不确定的,它的值取决于错误的堆栈信息。
其他的属性,比如fileName,lineNumber,columnNumber,line等,他们是由Mozilla提供的,它们的值取决于浏览器的实现。
3. Error的抛出
Error对象是通过throw关键字来抛出的,它的抛出形式有两种:
throw new Error()
throw 'error message'
第一种形式是抛出一个Error对象,第二种形式是抛出一个字符串,它们的区别是:
* 第一种形式抛出的是一个`Error`对象,它拥有`error`对象的所有属性和方法,比如`name`,`message`,`stack`等;
* 第二种形式抛出的是一个字符串,它只有`message`属性,没有`name`属性,也没有`stack`属性。
通常情况下,我们都是抛出一个Error对象,而不是抛出一个字符串。
4. Error的捕获
Error对象是通过try...catch关键字来捕获的,它的捕获形式有两种:
try...catch
try...catch...finally
try {
// ...
} catch (error) {
// ...
} finally {
// ...
}
关于catch语句可以省略遗产捕获的参数,或者不写catch,但是并不是所有的浏览器都支持,比如IE浏览器就不支持。
try {
// ...
} catch {
// ...
} finally {
// ...
}
try {
// ...
} finally {
// ...
}
5. 自定义Error
在es6之前,Error如果要实现自定义的错误,只能通过prototype来实现,比如:
function MyError(message, fileName, lineNumber) {
var instance = new Error(message, fileName, lineNumber);
Object.setPrototypeOf(instance, CustomError.prototype);
if (Error.captureStackTrace) {
Error.captureStackTrace(instance, CustomError);
}
return instance;
}
Object.setPrototypeOf(MyError.prototype, Error.prototype);
Object.setPrototypeOf(MyError, Error);
MyError.prototype.name = 'MyError';
try {
throw new MyError('error message');
} catch(e) {
console.error(e.name); // MyError
console.error(e.message); // error message
}
在es6之后,Error可以通过class来实现自定义的错误,比如:
class MyError extends Error {
constructor(message) {
super(message);
this.name = 'MyError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this, MyError);
}
}
}
try {
throw new MyError('baz', 'error message');
} catch(e) {
console.error(e.name); // MyError
console.error(e.message); // error message
}
6. 浏览器内置的Error
在浏览器的Error类型中,Error是一个基类,它的子类有EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError等。
try {
throw new EvalError('error message');
} catch(e) {
console.error(e.name); // EvalError
console.error(e.message); // error message
}
它们都是继承自Error的,所以它们都拥有Error的所有属性和方法,它们之间的区别是,在不同的情况下,会抛出不同的错误。
它们并没有太多区别,只是用于提示用户在不同的情况下,用于描述错误的信息,使用户更好的理解错误的原因。
本质上它们都是Error的子类,所以它们都可以通过instanceof来判断,比如:
try {
throw new EvalError('error message');
} catch(e) {
console.error(e instanceof Error); // true
console.error(e instanceof EvalError); // true
}
结语
Error是JavaScript中非常重要的一个类型,它用于描述错误的信息,使用户更好的理解错误的原因,同时也是开发者非常头疼的一个类型,愿开发的过程中无Error。