21 错误处理与调试

2 错误处理

2.1 try/catch 语句

ECMA-262 第 3 版新增了 try/catch 语句,作为在 JavaScript 中处理异常的一种方式。基本的语法如下所示,跟 Java 中的 try/catch 语句一样:

try { 
 	// 可能出错的代码
} catch (error) { 
 	// 出错时要做什么
} 

任何可能出错的代码都应该放到 try 块中,而处理错误的代码则放在 catch 块中,如下所示:

try { 
 	window.someNonexistentFunction(); 
} catch (error){ 
 	console.log("An error happened!"); 
} 

如果 try 块中有代码发生错误,代码会立即退出执行,并跳到 catch 块中。catch 块此时接收到一个对象,该对象包含发生错误的相关信息。与其他语言不同,即使在 catch 块中不使用错误对象,也必须为它定义名称。错误对象中暴露的实际信息因浏览器而异,但至少包含保存错误消息的 message属性。ECMA-262 也指定了定义错误类型的 name 属性,目前所有浏览器中都有这个属性。因此,可以像下面的代码这样在必要时显示错误消息:

try { 
 	window.someNonexistentFunction(); 
} catch (error){ 
 	console.log(error.message); 
} 

这个例子使用 message 属性向用户显示错误消息。message 属性是唯一一个在 IE、Firefox、Safari、Chrome 和 Opera 中都有的属性,尽管每个浏览器添加了其他属性。IE 添加了 description 属性(其值始终等于 message)和 number 属性(它包含内部错误号)。Firefox 添加了 fileName、lineNumber和 stack(包含栈跟踪信息)属性。Safari 添加了 line(行号)、sourceId(内部错误号)和 sourceURL属性。同样,为保证跨浏览器兼容,最好只依赖 message 属性。

2.1.1 finally 子句

try/catch 语句中可选的 finally 子句始终运行。如果 try 块中的代码运行完,则接着执行 finally 块中的代码。如果出错并执行 catch 块中的代码,则 finally 块中的代码仍执行。try 或 catch 块无法阻止 finally 块执行,包括 return 语句。比如:

function testFinally(){ 
 	try { 
 		return 2; 
 	} catch (error){ 
 		return 1; 
 	} finally { 
 		return 0; 
 	} 
} 

这个函数在 try/catch 语句的各个部分都只放了一个 return 语句。看起来该函数应该返回 2,因为它在 try 块中,不会导致错误。但是,finally 块的存在导致 try 块中的 return 语句被忽略。因此,无论什么情况下调用该函数都会返回 0。如果去掉 finally 子句,该函数会返回 2。如果写出 finally 子句,catch 块就成了可选的(它们两者中只有一个是必需的)。

注意 只要代码中包含了 finally 子句,try 块或 catch 块中的 return 语句就会被忽略,理解这一点很重要。在使用 finally 时一定要仔细确认代码的行为。

2.1.2 错误类型

代码执行过程中会发生各种类型的错误。每种类型都会对应一个错误发生时抛出的错误对象。ECMA-262 定义了以下 8 种错误类型:

  • Error
  • InternalError
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Error 是基类型,其他错误类型继承该类型。因此,所有错误类型都共享相同的属性(所有错误对象上的方法都是这个默认类型定义的方法)。浏览器很少会抛出 Error 类型的错误,该类型主要用于开发者抛出自定义错误。

InternalError 类型的错误会在底层 JavaScript 引擎抛出异常时由浏览器抛出。例如,递归过多导致了栈溢出。这个类型并不是代码中通常要处理的错误,如果真发生了这种错误,很可能代码哪里弄错了或者有危险了。

EvalError 类型的错误会在使用 eval()函数发生异常时抛出。ECMA-262 规定,“如果 eval 属性没有被直接调用(即没有将其名称作为一个 Identifier ,也就是 CallExpression 中的 MemberExpression),或者如果 eval 属性被赋值”,就会抛出该错误。基本上,只要不把 eval()当成函数调用就会报告该错误:

待补充 703

2.1.3 try/catch的用法

当 try/catch 中发生错误时,浏览器会认为错误被处理了,因此就不会再使用本章前面提到的机制报告错误。如果应用程序的用户不懂技术,那么他们即使看到错误也看不懂,这是一个理想的结果。使用 try/catch 可以针对特定错误类型实现自定义的错误处理。

try/catch 语句最好用在自己无法控制的错误上。例如,假设你的代码中使用了一个大型 JavaScript库的某个函数,而该函数可能会有意或由于出错而抛出错误。因为不能修改这个库的代码,所以为防止这个函数报告错误,就有必要通过 try/catch 语句把该函数调用包装起来,对可能的错误进行处理。

如果你明确知道自己的代码会发生某种错误,那么就不适合使用 try/catch 语句。例如,如果给函数传入字符串而不是数值时就会失败,就应该检查该函数的参数类型并采取相应的操作。这种情况下,没有必要使用 try/catch 语句。

2.2 抛出错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值