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 属性,目前所有浏览器中都有这个属性。因此,可以
错误处理
function testFinally(){
try { 20
像下面的代码这样在必要时显示错误消息:
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 属性。
finally 子句
try/catch 语句中可选的 finally 子句始终运行。如果 try 块中的代码运行完,则接着执行
finally 块中的代码。如果出错并执行 catch 块中的代码,则 finally 块中的代码仍执行。try 或 catch 块无法阻止 finally 块执行,包括 return 语句。比如:
return 2;
} catch (error){
return 1;
} finally {
return 0;
} }
这个函数在 try/catch 语句的各个部分都只放了一个 return 语句。看起来该函数应该返回 2, 因为它在 try 块中,不会导致错误。但是,finally 块的存在导致 try 块中的 return 语句被忽略。 因此,无论什么情况下调用该函数都会返回 0。如果去掉 finally 子句,该函数会返回 2。如果写出 finally 子句,catch 块就成了可选的(它们两者中只有一个是必需的)。
错误类型
代码执行过程中会发生各种类型的错误。每种类型都会对应一个错误发生时抛出的错误对象。 ECMA-262 定义了以下 8 种错误类型:
Error
InternalError EvalError
RangeError
ReferenceError SyntaxError
TypeError
URIError
注意 只要代码中包含了finally子句,try块或catch块中的return语句就会被忽 略,理解这一点很重要。在使用 finally 时一定要仔细确认代码的行为。
Error 是基类型,其他错误类型继承该类型。因此,所有错误类型都共享相同的属性(所有错误对
上的方法都是这个默认类型定义的方法)。浏览器很少会抛出 Error 类型的错误,该类型主要用于开 发者抛出自定义错误。
InternalError 类型的错误会在底层 JavaScript 引擎抛出异常时由浏览器抛出。例如,递归过多导 致了栈溢出。这个类型并不是代码中通常要处理的错误,如果真发生了这种错误,很可能代码哪里弄错 了或者有危险了。
EvalError 类型的错误会在使用 eval()函数发生异常时抛出。ECMA-262 规定,“如果 eval 属性 没有被直接调用(即没有将其名称作为一个 Identifier,也就是 CallExpression 中的 MemberExpression),或者如果 eval 属性被赋值”,就会抛出该错误。基本上,只要不把 eval()当 成函数调用就会报告该错误:
new eval(); // 抛出EvalError eval = foo; // 抛出EvalError
实践中,浏览器不会总抛出 EvalError。Firefox 和 IE 在上面第一种情况下抛出 TypeError,在 第二种情况下抛出 EvalError。为此,再加上代码中不大可能这样使用 eval(),因此几乎遇不到这种 错误。
RangeError 错误会在数值越界时抛出。例如,定义数组时如果设置了并不支持的长度,如-20 或 Number.MAX_VALUE,就会报告该错误:
let items1 = new Array(-20); // 抛出RangeError let items2 = new Array(Number.MAX_VALUE); // 抛出RangeError
RangeError 在 JavaScript 中发生得不多。
ReferenceError 会在找不到对象时发生。(这就是著名的"object expected"浏览器错误的原 因。)这种错误经常是由访问不存在的变量而导致的,比如:
let obj = x; // 在x没有声明时会抛出ReferenceError
SyntaxError 经常在给 eval()传入的字符串包含 JavaScript 语法错误时发生,比如:
eval("a ++ b"); // 抛出SyntaxError
在 eval()外部,很少会用到 SyntaxError。这是因为 JavaScript 代码中的语法错误会导致代码无 法执行。
TypeError 在 JavaScript 中很常见,主要发生在变量不是预期类型,或者访问不存在的方法时。很 多原因可能导致这种错误,尤其是在使用类型特定的操作而变量类型不对时。下面是几个例子:
let o = new 10; // 抛出TypeError console.log("name" in true); // 抛出TypeError Function.prototype.toString.call("name"); // 抛出TypeError
在给函数传参数之前没有验证其类型的情况下,类型错误频繁发生。
最后一种错误类型是 URIError,只会在使用 encodeURI()或 decodeURI()但传入了格式错误的 URI 时发生。这个错误恐怕是 JavaScript 中难得一见的错误了,因为上面这两个函数非常稳健。