24.错误处理机制
24.1 Error 实例对象
-
JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供
Error
构造函数,所有抛出的错误都是这个构造函数的实例。 -
message:错误提示信息
//Error()构造函数接受一个参数,表示错误提示,可以从实例的message属性读到这个参数。 var err = new Error('出错了'); err.message // "出错了" //Error实例对象必须有message属性,表示出错时的提示信息,没有提到其他属性。大多数 JavaScript 引擎,对Error实例还提供name和stack属性,分别表示错误的名称和错误的堆栈,但它们是非标准的,不是每种实现都有。
-
name:错误名称(非标准属性)
if (error.name) { console.log(error.name + ': ' + error.message); }
-
stack:错误的堆栈(非标准属性)
//stack属性用来查看错误发生时的堆栈。 function throwit() { throw new Error(''); } function catchit() { try { throwit(); } catch(e) { console.log(e.stack); // print stack trace } } catchit() // Error // at throwit (~/examples/throwcatch.js:9:11) // at catchit (~/examples/throwcatch.js:3:9) // at repl:1:5 ---------------- 错误堆栈的最内层是throwit函数,然后是catchit函数,最后是函数的运行环境。
24.2 原生错误类型
Error
实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他6种错误对象。也就是说,存在Error
的6个派生对象。
-
SyntaxError
对象【都是在语法解析阶段就可以发现】是解析代码时发生的语法错误。
// 变量名错误 var 1a; // Uncaught SyntaxError: Invalid or unexpected token //“token 非法” // 缺少括号 console.log 'hello'); // Uncaught SyntaxError: Unexpected string //“字符串不符合要求”
-
ReferenceError
对象引用一个不存在的变量时发生的错误。
// 使用一个不存在的变量 unknownVariable // Uncaught ReferenceError: unknownVariable is not defined //将一个值分配给无法分配的对象,比如对函数的运行结果赋值 // 等号左侧不是变量 console.log() = 1 // Uncaught ReferenceError: Invalid left-hand side in assignment
-
RangeError
对象是一个值超出有效范围时发生的错误。主要有几种情况:
- 数组长度为负数
Number
对象的方法参数超出范围,以及函数堆栈超过最大值。
// 数组长度不得为负数 new Array(-1) // Uncaught RangeError: Invalid array length
-
TypeError
对象变量或参数不是预期类型时发生的错误。
比如,对字符串、布尔值、数值等原始类型的值使用
new
命令,就会抛出这种错误,因为new
命令的参数应该是一个构造函数。new 123 // Uncaught TypeError: 123 is not a constructor var obj = {}; //调用对象不存在的方法,也会抛出TypeError错误,因为obj.unknownMethod的值是undefined,而不是一个函数。 obj.unknownMethod() // Uncaught TypeError: obj.unknownMethod is not a function
-
URIError
对象URI 相关函数的参数不正确时抛出的错误,主要涉及
encodeURI()
、decodeURI()
、encodeURIComponent()
、decodeURIComponent()
、escape()
和unescape()
这六个函数。decodeURI('%2') // URIError: URI malformed
-
EvalError
对象eval
函数没有被正确执行时,会抛出EvalError
错误。该错误类型已经不再使用了,只是为了保证与以前代码兼容,才继续保留。
以上这6种派生错误,连同原始的Error
对象,都是构造函数。开发者可以使用它们,手动生成错误对象的实例。这些构造函数都接受一个参数,代表错误提示信息(message)。
24.3自定义错误
function UserError(message) {
this.message = message || '默认信息';
this.name = 'UserError';
}
//让它继承Error对象
UserError.prototype = new Error();
UserError.prototype.constructor = UserError;
--------------------
new UserError('这是自定义的错误!');
24.4throw 语句【throw
可以抛出任何类型的值。也就是说,它的参数可以是任何值。】
throw
语句的作用是手动中断程序执行,抛出一个错误。
var x = -1;
if (x <= 0) {
throw new Error('x 必须为正数');
}
// Uncaught Error: x 必须为正数
//抛出自定义错误
//throw抛出的是一个UserError实例。
function UserError(message) {
this.message = message || '默认信息';
this.name = 'UserError';
}
throw new UserError('出错了!');
// Uncaught UserError {message: "出错了!", name: "UserError"}
24.5 try…catch 结构
允许对错误进行处理,选择是否往下执行。
try {
throw new Error('出错了!');
} catch (e) {
console.log(e.name + ": " + e.message);
console.log(e.stack);
}
// Error: 出错了!
// at <anonymous>:3:9
// ...
//try代码块抛出错误(上例用的是throw语句),JavaScript 引擎就立即把代码的执行,转到catch代码块,或者说错误被catch代码块捕获了。catch接受一个参数,表示try代码块抛出的值。
如果你不确定某些代码是否会报错,就可以把它们放在try...catch
代码块之中,便于进一步对错误进行处理。catch
代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。
try {
foo.bar();
} catch (e) {
//catch捕获错误之后,会判断错误类型(EvalError还是RangeError),进行不同的处理。
if (e instanceof EvalError) {
console.log(e.name + ": " + e.message);
} else if (e instanceof RangeError) {
console.log(e.name + ": " + e.message);
}
// ...
}
24.6finally 代码块
try...catch
结构允许在最后添加一个finally
代码块,表示不管是否出现错误,都必需在最后运行的语句。
function cleansUp() {
try {
throw new Error('出错了……');
console.log('此行不会执行');
} finally {
console.log('完成清理工作');
}
}
cleansUp()
// 完成清理工作
// Uncaught Error: 出错了……
// at cleansUp (<anonymous>:3:11)
// at <anonymous>:10:1
上面代码中,由于没有catch
语句块,一旦发生错误,代码就会中断执行。中断执行之前,会先执行finally
代码块,然后再向用户提示报错信息。