总所周知,当系统运行出现错误的时候,就会抛出一个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
。