一、错误处理方案
- 开发中我们会封装一些工具函数,在使用的过程中,可能会传递一些参数;
- 对于函数来说,需要对这些参数进行验证,否则可能得到的是我们不想要的结果;
- 很多时候我们可能验证到不是希望得到的参数时,就会直接return,但这个时候会存在一些问题:
- 别的同事调用你的函数时,不知道是因为函数内部没有正常执行,还是执行结果就是一个undefined;
- 正确的做法应该是如果没有通过某些验证,那么应该让外界知道函数内部报错了;
- 通过throw关键字,抛出一个异常;
- throw语句用于抛出一个用户自定义的异常;
- 当遇到throw语句时,当前的函数执行会被停止(throw后面的语句不会执行);
function sum(num1, num2) { // 当传入的参数的类型不正确时, 应该告知调用者一个错误 if (typeof num1 !== "number" || typeof num2 !== "number") { throw "parameters is error type~" } return num1 + num2 } console.log(sum({ name: "yzh" }, true)) console.log("后续的代码会继续运行~")
二、throw关键字
- throw表达式就是在throw后面可以跟上一个表达式来表示具体的异常信息;
- throw关键字可以跟上的类型:
- 基本数据类型:比如number、string、Boolean
- 对象类型:对象类型可以包含更多的信息
function foo(type) { console.log("foo函数开始执行") if (type === 0) { // 1.抛出一个字符串类型(基本的数据类型) throw "error" // 2.比较常见的是抛出一个对象类型 // throw { errorCode: -1001, errorMessage: "type不能为0~" } // 强调: 如果函数中已经抛出了异常, 那么后续的代码都不会继续执行了 console.log("foo函数后续的代码") } console.log("foo函数结束执行") } foo(0) console.log("后续的代码继续执行~")
- 对于对象类型,我们可以封装一个类:
class MyError { constructor(errorCode, errorMessage) { this.errorCode = errorCode this.errorMessage = errorMessage } } function foo(type) { if (type === 0) { throw new MyError(-1001, "type不能为0~"); } } //MYError { errorCode: -1001, errorMessage: 'type不能为0~' } foo(0);
三、Error类型
- JS已经给我们提供了一个Error类,我们可以直接创建这个类的对象;
- Error包含三个属性:
- messsage:创建Error对象时传入的message;
- name:Error的名称,通常和类的名称一致;
- stack:整个Error的错误信息,包括函数的调用栈,当我们直接打印Error对象时,打印的就是stack;
function foo(type) { if (type === 0) { const err = new Error("type不能为0") err.name = "yzh" err.stack = "aaaa" throw err } } // [aaaa] { name: 'yzh' } foo(0)
- Error有一些自己的子类:
- RangeError:下标值越界时使用的错误类型;
- SyntaxError:解析语法错误时使用的错误类型;
- TypeError:出现类型错误时,使用的错误类型;
function foo(type) { if (type === 0) { const err = new TypeError("当前type类型是错误的~") throw err } } //TypeError: 当前type类型是错误的~ foo(0)
四、异常的处理
- 如果我们在调用一个函数时,这个函数抛出了异常,但是我们并没有对这个异常进行处理,那么这个异常会继续传递递到上一个函数调用中;
- 而如果到了最顶层(全局)的代码中依然没有对这个异常的处理代码,这个时候就会报错并且终止程序的运行;
function foo(type) { if (type === 0) { throw new Error("foo error message~") } } function bar() { foo(0) } function test() { bar() } //Error: foo error message~ test(); console.log("后续的代码执行~")
五、异常的捕获
- 当出现异常时,我们并不希望程序直接退出,而是希望可以正确的处理异常;
function bar() { try { foo(0) console.log("bar函数后续的继续运行") } catch(err) { console.log("bar err:", err.message) } finally { console.log("finally代码执行~") } } /* bar err: foo error message~ finally代码执行~ 后续的代码执行~ */ test();
5.1. try...catch
-
try...catch语句标记要尝试的语句块,并指定一个出现异常时抛出的响应;try { foo(); } catch (error) { console.error(error); // ReferenceError: foo is not defined // 注意!错误消息因浏览器而异 } -
语法:
try { try_statements } catch (exception_var_1 if condition_1) { catch_statements_1 } catch (exception_var_2) { catch_statements_2 } finally { finally_statements }try_statements需要被执行的语句;exception_var_1,exception_var_2用于保存关联catch子句的异常对象的标识符;condition_1一个条件表达式;catch_statements_1,catch_statements_2如果在try块里有异常被抛出时执行的语句;finally_statements在try语句块之后执行的语句块。无论是否有异常抛出或捕获这些语句都将执行;
-
描述:
try语句包含了由一个或者多个语句组成的try块,和至少一个catch块或者一个finally块的其中一个,或者两个兼有,下面是三种形式的try声明:try...catchtry...finallytry...catch...finally
-
示例:
- 嵌套 try 块
try { try { throw new Error("oops"); } finally { console.log("finally"); } } catch (ex) { console.error("outer: ", ex.message); } // finally // outer: oops - 如果我们已经在 try 语句中,通过增加一个 catch 语句块捕获了异常
try { try { throw new Error("oops"); } catch (ex) { console.error("inner:", ex.message); } finally { console.log("finally"); } } catch (ex) { console.error("outer:", ex.message); } // inner:oops // finally - 再次抛出错误
try { try { throw new Error("oops"); } catch (ex) { console.error("inner:", ex.message); throw ex; } finally { console.log("finally"); } } catch (ex) { console.error("outer:", ex.message); } // inner:oops // finally // outer:oops任何给定的异常只会被离它最近的封闭 catch 块捕获一次。当然,在“inner”块抛出的任何新异常(因为 catch 块里的代码也可以抛出异常),将会被“outer”块所捕获;
- 从 finally 语句块返回
try { try { throw new Error("oops"); } catch (ex) { console.error("inner:", ex.message); throw ex; } finally { console.log("finally"); return; } } catch (ex) { console.error("outer:", ex.message); } // inner:oops // finally
- 嵌套 try 块