JS中异常处理的理解
JS里的异常处理
JS的异常捕获与处理可以从它的 try-catch 语法结构说起,具体形式如下:
try{ ... //异常的抛出 }catch(e){ ... //异常的捕获与处理 }finally{ ... //结束处理 }
其中,try块:
try块包含的是可能产生异常的代码,在这里面直接或者在里面通过调用函数里间接抛出的异常都可以捕获到。部分浏览器还可以找到具体抛出的位置。详见e.stack。
catch块:
catch块,是捕获异常,并处理异常的地方,包括条件捕获和非条件捕获。
//条件捕获与非条件捕获 try { throw new Err(); }catch(e instanceof ErrBob) { console.log(e.name + ' Bob''); }catch(e instanceof ErrTom) { console.log(e.name + ' Tom''); }catch(e instanceof ErrLily) { console.log(e.name + ' Lily''); }catch(e) { console.log('that's all'); }
条件捕获,如 catch(e instanceof obj) 的形式,用 instanceof 判断异常的对象类型,实现指定的异常处理方式。
非条件捕获,如 catch(e) 的形式,当异常抛出时,无论异常的类型都进行捕获并处理。
这里有两点注意,如果条件捕获和非条件捕获共用,那么非条件捕获必须放在最后,因为它是无条件的捕获类型,捕获后会忽略后面的任意 catch 块。
另外,对异常的处理必须考虑周全,在 catch 里要么处理所有的异常,要么再次抛出异常(假定外层还有异常处理),否则在调试过程中会非常困难,因为出现的异常被忽略了。
finally块:
无论是否捕获异常,都会在 try 或 catch块后立即执行。
finally块常常用以文件的关闭,标记的取消等操作,更多的时候作为一种 ”优雅的失败“ 而存在,常常代替 catch 块。
在JS的DOM对象中,还有一个 window.onerror 作为事件监听来从全局处理JS运行时的错误。由于浏览器的差异,实际上许多错误事件不能触发 window.onerror ,因此要小心使用,详见《Why window.onerror Is Not Enough》。
那么如何抛出异常呢?
JS里用 throw 指定一个用户定义的异常类型,并抛出。抛出点可以在 try 或 catch 块中。
throw e; //抛出用于自定义的异常 throw 'error'; throw '21'; throw true; throw new myError();
这里的异常类型包括字符串、数字、布尔值和对象,如例子中所示。为了获取有用的信息,以及有条件地捕获异常,其中只有对象类型最为常用。
JS里内置的Error对象方便我们使用,‘throw new Error();’ ,同时提供了6种错误类型便于我们捕获,包括EvalError、RangeError、ReferenceError、SyntaxError、 TypeError、URIError,详见这里。
更为便利的是定制一个异常的对象,可以自定义,也可以继承Error对象,主要包括 name 和 message 属性即可,例如:
try{ throw { name : 'err1', message : 'here it is' }; }catch(e){ console.log(e.name + ' : ' + e.message); }
JS里异常处理的有两个特点:
1、活动链域和性能
当对异常进行捕获并进入到 catch 块中,此时的异常对象 e 将成为一个新的活动对象,并提到活动链域的最前面。如下栗子:
try{ ... }catch(e){ var name = 'jberry'; alert(name + e.message); //e 在活动链域的最前面
//handleFn(e);
}
此时 catch 块中的任何标识符(例子中的 ‘name’)都将在活动链域的第二个活动对象里访问,这样降低了访问的性能。好的方法的是调用异常处理函数,减少在catch块中对标识符的访问(例子中 ‘handleFn(e);')。
2、错误和异常有什么区别?
在如Java一些语言中,错误和异常有所区别,它们分属不同的类别。
通常错误是非正常的系统级的严重错误,出现后程序直接终止,这种错误是不应该、或是不可预见的,不推荐用 try-catch 来捕获处理。
异常是程序运行时不满足某些条件而出现的非严重的错误,应尽量使用 try-catch 来捕获它。
而在JS中,只定义了错误(Error),作为其内置的对象,其原型对象一般包括 name 和 message 两个属性。不同的浏览器还实现了不同的错误类型以及附加的属性和方法。
异常(Exception)只是错误的另一种说法,它们实际上一个东西,都可以用 try-catch 来处理,因此不用在意它们的处理方式。一个异常的对象,在JS里实际上就是一个拥有 name 和 message 属性的Error实例罢了。
唯一不同的是,如上面所述,JS中异常可以以字符串、数字、布尔值或对象的形式来抛出处理,而错误则通常特指Error对象及其继承的自定义子对象。