JavaScript错误处理操作实例详解
本文详解JavaScript错误处理机制,涵盖try-catch-finally语句、七种内置错误类型及自定义错误抛出。深入探讨类型转换与数据校验、通信错误处理,并介绍利用Image对象将错误日志上报至服务器的最佳实践,旨在提升代码健壮性与可维护性。
本文详细解析JavaScript中的错误处理机制,提供具体操作示例供参考。
完善的错误处理机制能够及时向用户发出提示,因此了解JavaScript提供的错误处理工具与方法至关重要。
1 try-catch 语句
ECMA-262 第 3 版引入了 try-catch 语句,这已成为JavaScript处理异常的标准方式。
try{
//可能会导致错误的代码
} catch (error){
//错误处理
}
当 try 块中的代码发生错误时,程序会立即跳转执行 catch 块。catch 块接收一个包含错误信息的对象,该对象具有 message 属性,用于存储浏览器提供的具体错误消息。
<script type="text/javascript">
try {
window.someNonexistenceFunction();
} catch (error) {
console.log(error.message);
}
</script>
message 属性在所有浏览器中均受支持,因此在跨浏览器开发中,建议优先使用该属性获取错误信息。
1.1 finally 子句
finally 子句为可选部分,但其中的代码无论发生何种情况(包括 return 语句)都会被执行。
<script type="text/javascript">
function testFinally() {
try {
return 2;
} catch (error) {
return 1;
} finally {
return 0;
}
}
console.log(testFinally());//0
</script>
IE7 及更早版本存在一个缺陷:若未定义 catch 子句,finally 中的代码将不会执行;该问题在 IE8 中得到修复。
注意:一旦代码中使用 finally 子句,无论 return 语句位于 try 还是 catch 块中,其返回值均会被忽略。
1.2 错误类型
当错误发生时,系统会抛出对应类型的错误对象。ECMA-262 定义了以下 7 种错误类型:
- Error
- EvalError
- RangeError
- ReferenceError
- SyntaxError
- TypeError
- URIError
1.2.1 Error
Error 是基类型,其他所有错误类型均继承自它。开发者可以利用 Error 来定义自定义错误类型。
1.2.2 EvalError
当使用 函数发生异常时会抛出 EvalError。具体而言,若未将 作为函数调用,则会抛出此错误。
new eval();//抛出 EvalError
eval = foo;//抛出 EvalError
实际开发中极少如此调用 eval() 函数(除非用户思维异常),因此 EvalError 鲜少被触发。
1.2.3 RangeError
当数值超出规定范围时抛出 RangeError。例如,定义数组时指定了不支持的项数,便会触发该错误。
var item1 = new Array(-20);//抛出 RangeError
var item1 = new Array(Number.MAX_VALUE);//抛出 RangeError
1.2.4 ReferenceError
当访问不存在的变量时抛出 ReferenceError(即常见的“object expected”错误)。
var obj = x;//x 还未被声明,所以抛出 ReferenceError
1.2.5 SyntaxError
当将包含错误语法的字符串传入 eval() 函数时,会抛出 SyntaxError。
eval("a ++ b");//抛出 SyntaxError
在 eval() 函数外部发生的语法错误会导致 JavaScript 立即停止执行,因此不会抛出此类错误。
1.2.6 TypeError
当变量保存了意外类型,或访问不存在的方法时,会抛出 TypeError。此错误较为常见。
var o = new 10;//抛出 TypeError
alert("name" in true);//抛出 TypeError
Function.prototype.toString.call("name");//抛出 TypeError
若传递给函数的参数类型与预期不符,同样会抛出此错误。
1.2.7 URIError
使用 encodeURI() 或 decodeURI() 时,若 URI 格式不正确,将抛出 URIError。由于这两个函数容错性极高,此类错误较少发生。
开发者可针对上述错误类型进行针对性处理。
try{
someFunction();
} catch (error){
if (error instanceof TypeError){
//处理类型错误
}
...
}
由于不同浏览器的 message 内容存在差异,跨浏览器编程时建议直接检查错误类型。
1.3 合理使用 try-catch
try-catch 最适合处理无法控制的错误,例如调用无法修改源码的开源库函数时。
对于自定义函数,验证参数合法性时应避免使用 try-catch,而应在调用参数前直接进行验证,因为此类代码由开发者控制。
2 抛出错误
throw 操作符用于抛出自定义错误,必须指定一个值(任意类型)。代码遇到 throw 时立即停止执行,仅在 try-catch 捕获到该值后继续执行。
利用内置错误类型可模拟浏览器错误,这些类型的构造函数均接收一个参数,即具体的错误消息。
throw new Error("Something bad happened.");
最常用 Error、RangeError、ReferenceError 和 TypeError 来创建自定义错误消息。
也可利用原型链继承 Error 来创建自定义消息,例如为新错误类型指定 name 和 message 属性。
<script type="text/javascript">
function CustomError(message) {
this.name = "CustomError";
this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError("My message");
</script>
这样创建的自定义错误与浏览器原生错误不同,具有一定的实用价值。
注意:仅在抛出 Error 对象时,IE 才会显示自定义错误消息;其他错误对象在 IE 中仅显示“exception thrown and not caught”。
2.1 抛出错误的时机
应在已知特定错误条件(导致函数无法正常执行)时抛出自定义错误。
<script type="text/javascript">
function process(values) {
if (!(values instanceof Array)) {
throw new Error("process():Argument must be an array.");
}
values.sort();
for (var i = 0, len = values.length; i < len; i++) {
if (values[i] > 100) {
return values[i];
}
}
return -1;
}
process("hi");
</script>
若向上述函数传入字符串参数,sort() 将报错,因此加入带有适当消息的自定义错误。这对于数千行代码的项目而言,能显著提升可维护性。
错误消息应包含函数名称及错误原因的明确描述,以确保清晰易懂。
开发时需关注可能导致函数失败的因素,并添加相应的自定义错误。良好的错误处理机制确保代码仅抛出定义好的错误。
2.2 抛出错误与使用 try-catch
建议在抛出错误时提供详尽信息,以便在维护时能准确定位错误发生的位置及原因。
3 错误事件
任何未被 try-catch 处理的错误都会触发 window 对象的 error 事件(IE、Firefox 和 Chrome 均支持)。该事件接收三个参数:错误消息、错误所在 URL 和行号,通常仅错误消息有用。只能通过 DOM0 级技术指定 onerror 事件处理程序,若返回 false,可阻止浏览器报告错误的默认行为。
<script type="text/javascript">
window.onerror= function (message,url,line) {
console.log(message);
return false;
}
</script>
此函数相当于整个文档的 try-catch 语句,可捕获所有未处理的运行时错误。理想情况下,错误应包含在 try-catch 中,因此通常不使用此方法。
注意:不同浏览器对此函数的处理方式不同。在 IE 中,发生 onerror 事件后代码仍继续执行,变量和数据保留;而在 Firefox 中,代码停止执行,之前的变量和数据被销毁。
图像也支持 error 事件。若图像的 src 属性中的 URL 无法返回被识别的图像格式,将触发 error 事件,此时返回以图像为目标的 event 对象。
<script type="text/javascript">
var image = new Image();
EventUtil.addHandler(image, "load", function (event) {
console.log("Image loaded!");
});
EventUtil.addHandler(image, "error", function (event) {
console.log("Image not loaded!");
});
image.src = "smilex.gif";//实际并不存在
</script>
注意:若发生 error 事件,表明图像下载过程已结束。
4 常见的错误类型
由于 JavaScript 是松散类型语言,错误仅在代码运行期间发生。通常需重点关注以下三种错误:
① 类型转换错误 ② 数据类型错误 ③ 通信错误
4.1 类型转换错误
使用相等(==)或不相等(!==),或在 if、for、while 中使用非布尔值时,最常发生类型转换错误。
建议使用全等(===)和不全等(!==)来避免类型转换操作。
if 等语句会自动将任何值转换为布尔值。
function concat(str1, str2, str3){
var result = str1 + str2;
if (str3){//不要这样!!!
result +=str3;
}
return result;
}
该函数旨在拼接两个或三个字符串并返回结果,因此第三个参数为可选。必须进行检查:若仅使用前两个参数调用,第三个参数作为未使用变量被自动赋值为 undefined,在 if 中转换为 false,逻辑成立。但若传入数值 0,在 if 中也会转换为 false,导致其未被加入 result。因此必须进行显式检查。
function concat(str1, str2, str3){
var result = str1 + str2;
if (typeof str3 == "string"){
result +=str3;
}
return result;
}
4.2 数据类型错误
function getQueryString(url){
var pos = url.indexOf("?");
if (pos > -1){
return url.substring(pos + 1);
}
return "";
}
该函数旨在返回给定 URL 中的查询字符串。若传入非字符串类型参数,将导致错误,因此需增加类型判断。
function getQueryString(url){
if(typeof url == "string"){
var pos = url.indexOf("?");
if (pos > -1){
return url.substring(pos + 1);
}
}
return "";
}
此外,在流控制语句中使用非布尔值也会导致数据类型错误。
function reverseSort(values){
if (values){//非数组值都会报错
values.sort();
values.reverse();
}
}
另一种错误是将参数与 null 进行比较,这仅能确保参数非 null 和 undefined,同样不建议将参数与 undefined 进行比较。
还有一种错误是仅针对某一特性进行检测。
function reverseSort(values){
if (typeof values.sort == "function"){
values.sort();
values.reverse();
}
}
上述函数若传入带有 sort() 方法的对象,将通过检测,但在调用 reverse() 方法时报错。因此最好使用 instanceof 进行检测。
function reverseSort(values){
if (values instanceof Array){
values.sort();
values.reverse();
}
}
总体而言,基本类型值使用 typeof 检测,对象值使用 instanceof 检测。特别是面向公众的 API,必须执行类型检查,以确保函数始终正常运行。
4.3 通信错误
JavaScript 与服务器之间的任何通信均可能产生错误。
一种通信错误是发送了不正确的 URL 格式数据,通常因未使用 encodeURIComponent() 对数据进行编码所致,可使用相关函数处理查询字符串。
/**
* 添加查询字符串
* @param url URL
* @param name 参数名
* @param value 参数值
* @returns {*}
*/
function addQueryStringArg(url, name, value) {
if (url.indexOf("?") == -1) {
url += "?";
} else {
url += "&";
}
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
尽量使用该函数,可确保编码正确。
5 区分致命错误与非致命错误
非致命错误可根据以下一个或多个条件确定:
- 不影响用户的主要任务;
- 只影响页面的一部分;
- 可以恢复;
- 重复操作可以消除错误。
而致命错误也可根据以下一个或多个条件确定:
- 无法继续执行;
- 影响到了用户的主要操作;
- 导致其他连带的错误。
若发生致命错误,应立即发送消息通知用户无法继续操作。若必须刷新页面才能恢复,也必须通知用户并提供刷新按钮。
例如,在大型网站中,可能存在多个互不依赖的模块,其初始化方式如下。
for (var i=0, len=mods.length; i<len; i++){
mods[i].init();
}
这样做的问题是,若有一个模块发生错误,将导致后续其他模块无法初始化,从而引发致命错误。通过改造,可将致命错误转化为非致命错误。
for (var i=0, len=mods.length; i<len; i++){
try{
mods[i].init();
} catch (ex){
...
}
}
6 把错误记录到服务器
建议集中保存错误日志,以便后续查找错误原因。可将 JavaScript 错误发送至服务器进行保存,实现前后端错误集中管理,便于数据分析。
首先需在服务器上创建一个接口,用于接收页面发送的错误数据。
/**
* 记录 JavaScript 错误
* @param sev 严重程度,比如:nonfatal
* @param msg 错误消息
*/
function logError(sev,msg){
var img=new Image();
img.src="log.action?sev="+encodeURIComponent(sev)+"&msg="+encodeURIComponent(msg);
}
使用 Image 对象发送请求具有以下好处:
- 所有浏览器均支持 Image 对象,包括那些不支持 XMLHttpRequest 对象的浏览器。
- 可避免跨域限制,例如可使用一台日志服务器专门接收多台 web 服务器抛出的错误。
只要使用了 try-catch 语句,就应将错误记录到日志中。
for (var i=0, len=mods.length; i<len; i++){
try{
mods[i].init();
} catch (ex){
logError("nonfatal","模块初始化失败:"+ex.message);
}
}
第二个参数包含上下文信息及 JavaScript 错误消息,附带上下文信息有助于分析导致错误的真正原因。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript错误与调试技巧总结》、《JavaScript传值操作技巧总结》、《javascript编码操作技巧总结》、《JavaScript中json操作技巧总结》、《JavaScript切换特效与技巧总结》、《JavaScript查找算法技巧总结》、《JavaScript动画特效与技巧汇总》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
