JavaScript错误处理操作实例详解

作者:小括号时间:2026-10-22 20:06:33浏览:128

本文详解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程序设计有所帮助。

作者最新文章