## 错误处理机制 **1、 try-catch语句** ECMA-262第3版引入了`try-catch`语句,作为JavaScript中处理异常的一种标准方式。 语法: ``` try{ // 可能会导致错误的代码 }catch (error){ // 在错误发生时怎么处理 } ``` 也就是说,我们应该把所有可能会抛出错误的代码都放在try语句块中,而把那些用于错误处理代码放在catch块中。 `try-catch`语句的逻辑是:如果try块中的任何代码发生了错误,就会立即退出代码执行过程,然后接着执行catch块。此时,catch块会接收到一个包含错误信息的对象。 注意:即使你不想使用这个错误对象,也要给它起个名字。 虽然这个对象在不同浏览器中可能包含不同信息,但是都有一个保存着错误消息的message属性,还有一个保存错误类型的name属性(并不是所有浏览器都有)。 ``` try{ }catch (error){ console.log(error.message); } ``` 在跨浏览器编程时,最好还是只使用message属性。 **1.1 finally子句** 当使用`finally`子句时,其代码无论如何都会执行,也就是说,不管是正常执行还是出错了,`finally`子句都会执行。甚至`return`语句,也不会阻止`finally`子句的执行。 看下面的例子: ``` function test(){ try{ console.log('a'); return 2; }catch(error){ console.log('b'); }finally{ console.log('c'); } } console.log(test()); //结果 a c 2 ``` 从运行结果,我们可以看到,`return`语句并没有阻止`finally`子句的执行,而且是在`finally`子句执行后才会返回`return`语句的值。 **2、错误类型** 执行代码期间可能会发生的错误有多种类型。每种错误都有对应的错误类型,而当错误发生时,会抛出相应类型的错误对象。 ECMA-262定义了下列7中错误类型: ``` Error EvalError RangeError ReferenceError SyntaxError TypeError URIError ``` Error是基类型,其他错误类型都继承自该类型。所有错误类型共享了一组相同的属性。 **(1)EvalError类型** EvalError类型的错误会在使用eval()函数而发生异常时抛出。简单的说,如果没有把eval()当成函数调用,就会抛出异常。比如: ``` new eval() // 抛出EvalError eval = foo; // 抛出EvalError ``` 注意:在ES5中已经不在出现了。 **(2)RangeError类型** RangeError类型的错误会在数值超出相应范围时触发。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。 ``` var item = new Array(-20); // 抛出RangeError异常 ``` **(3)ReferenceError类型** 在找不到对象的情况下,会发生ReferenceError。通常,在访问不存在的变量时,就会发生这种错误。 ``` var obj = x; // 在x并未声明的情况下抛出ReferenceError ``` **(4)SyntaxError类型** SyntaxError是解析代码时发生的语法错误。 ``` var 1a; // 变量名错误,抛出SyntaxError ``` **(5)TypeError类型** 在变量中保存着意外的类型,或在访问不存在的方法时,都会导致这种错误。 ``` var o = new 10; //抛出TypeError ``` **(6)URIError类型** URIError是URI相关函数的参数不正确时抛出的错误,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。 **2.2 抛出错误** 与try-catch语句相配的还有一个throw操作符,用于随时抛出自定义错误。抛出错误时,必须要给throw操作符指定一个值,这个值可以是任何类型。 ``` throw 1; throw 'tg'; throw true; throw {name: 'tg'}; ``` 上面的代码都是有效的。 在遇到throw操作符时,代码会立即停止运行。仅当有try-catch语句捕获到被抛出的值时,代码才会继续执行。 **2.3 Error对象** 所有抛出的错误都是Error构造函数的实例。Error构造函数接受一个参数,表示错误提示,可以从实例的message属性读到这个参数。 在JavaScript中,Error对象的实例必须有message属性,表示出错时的提示信息。在大多数JavaScript引擎中,Error实例还可能有name和stack属性,分别表示错误的名称和错误的堆栈。 ``` var err = new Error('出错了'); err.message; // "出错了" ``` **2.4 自定义错误** 我们还可以创建自定义错误消息,最常用的错误类型是Error、RangeError、ReferenceError和TypeError。 ``` throw new Error('报错了'); throw new RangeError('数组长度错误'); ``` 另外,利用原型链还可以通过继承Error来创建自定义错误类型: ``` function CustomError(message){ this.name = 'CustomError'; this.message = message; } CustomError.prototype = new Error(); throw new CustomError('我的错误信息'); ``` **3、错误(error)事件** 任何没有通过try-catch处理的错误都会触发window对象的error事件。 onerror事件处理程序不会创建event对象,但它接受三个参数:错误消息、错误所在的URL和行号。 ``` window.onerror = function(message, url, line){ }; ``` 当你在事件处理程序中返回false,可以阻止浏览器报告错误的默认行为 ``` window.onerror = function(message, url, line){ return false; }; ``` **4、调试技术** **4.1 alert方法** 在以前,大多数都是在要调试的代码中插入alert()函数,看是否执行到这一步来判断哪里出错,这种方式比较麻烦,因为alert()会阻止后续代码的执行(除非你关闭了alert弹窗),而且调试后还要清理。 **4.2 console** 随着浏览器的不断改善,现在的浏览器都有JavaScript控制台,我们可以向这些控制台输出消息,比如最常用的console对象,它的常用方法如下: - error(message):将错误消息记录到控制台 - info(message):将信息性消息记录到控制台 - log(message):将一般消息记录到控制台 - warn(message):将警告消息记录到控制台 ``` function test(){ console.log('结果:' + (1 + 2)); } ``` **4.3 throw** 使用throw抛出错误。