一.try-catch 语句
ECMA-262 第 3 版引入了 try-catch 语句,作为 JavaScript 中解决异样的一种规范形式。根本的语法如下所示,不言而喻,这与 Java 中的 try-catch 语句是完全相同的:
try {// 可能会导致谬误的代码} catch (error) {// 在谬误产生时怎么解决}
咱们应该把所有可能会抛出谬误的代码都放在 try 语句快中,而把那些用于错误处理的代码放在 catch 块中, 如下示例:
try {window.someNonexistentFunction(); // 调用不存在的函数
} catch (error) {alert('An error happened!');
}
如果 try 块中的任何代码产生了谬误,就会立刻退出代码执行过程,而后接着执行 catch 块,此时,catch 块会接管到一个蕴含错误信息的对象。与在其余语言中不同的是,即便你不想应用这个谬误对象,也要给它起个名字。这个对象中蕴含的理论信息会因浏览器而异,但独特的是有一个保留着错误信息的 message 属性。ECMA-262 还规定了一个保留着谬误类型的 name 属性,以后所有浏览器都反对这个属性(Opera9 之前的版本不反对这个属性)。因而,在产生谬误时,就能够像上面这样捕风捉影地显示浏览器给出的信息:
try {window.someNonexistentFunction(); // 调用不存在的函数
} catch (error) {alert(error.message);
}
这个例子在向用户显示错误信息时,应用了谬误对象的 message 属性,这个 message 属性是惟一一个能保障所有浏览器都反对的属性,除此之外,IE、Firefox、Safari、Chrome 以及 Opera 都为事件对象增加了其余相干信息。IE 增加了与 message 属性完全相同的 description 属性,还增加了保留着外部谬误数量的 number 属性。Firefox 增加了 fileName、lineNumber 和 stack(蕴含栈跟踪信息)属性。Safari 增加了 line(示意行号)、sourceId(示意外部错误代码)和 sourceUrl 属性。当然,在跨浏览器编程时,最好还是只应用 message 属性。
1. finally 子句
尽管在 try-catch 语句中是可选的,但 finally 子句一经应用,其代码无论如何都会执行。换句话说,try 语句块中的代码全副失常执行,finally 子句会执行;如果因为出错而执行了 catch 语句块,finally 子句照样还会执行。只有代码中蕴含 finally 子句,则无论 try 或 catch 语句块中蕴含什么样的代码——甚至 return 语句,都不会阻止 finally 子句的执行。来看上面这个函数:
function testFinally() {
try {return 2;} catch (error) {return 1;} finally {return 0;}
}
testFinally(); //0
这个函数在 try-catch 语句的每一部分都放了一条 return 语句。外表上看,调用这个函数会返回 2,因为返回 2 个 return 语句位于 try 语句块中,而执行该语句又不会出错。可是,因为最初还有一个 finally 子句,后果就会导致该 return 语句被疏忽,也就是说,调用这个函数只能返回 0,如果把 finally 子句拿掉,这个函数将返回 2.(请读者务必要记住,只有代码中蕴含 finally 子句,那么无论 try 还是 catch 语句块中的 return 语句都将被疏忽。因而,在应用 finally 子句之前,肯定要十分分明你想要代码怎么样)
- 谬误类型
执行代码期间可能会产生的谬误有多种类型,每种谬误都有对应的谬误类型,而当谬误产生时,就会抛出相应类型的谬误对象。ECMA-262 定义了下列 7 种谬误类型:
01, Error
02, EvalError
03, RangeError
04, ReferenceError
05, SyntaxError
06, TypeError
07, URIError
其中,Error 是基类型,其余谬误类型都继承自该类型,因而,所有谬误类型共享了一组雷同的属性(谬误对象中的办法全是默认的对象办法)。Error 类型的谬误很少见,如果有也是浏览器抛出的;这个基类型的次要目标是供开发人员抛出自定义谬误。
EvalError 类型的谬误是在应用 eval() 函数而产生异样时抛出。ECMA-262 中对这个谬误有如下形容:“示意全局函数 eval 的应用形式与其定义不相符。“除此之外,并没有救到底什么状况会引发这种谬误给出阐明。在理论开发中碰到这种谬误的可能性并不大。
RangeError 类型的谬误会在数值超出相应范畴时触发。例如,在定义数组时,如果指定了数组不反对的项数(如 -20 或 Number.MAX_VALUE),就会触发这种谬误。上面是具体的例子:
var items1 = new Array(-20); //VM77:1 Uncaught RangeError: Invalid array length(…)
var items2 = new Array(Number.MAX_VALUE); //VM79:1 Uncaught RangeError: Invalid array length(…)
JavaScript 中常常会呈现这种范畴谬误。
在找不到对象的状况下,会产生 ReferenceError(这种状况下,会间接导致人所共知的“object expected” 浏览器谬误)。通常,在拜访不存在的变量时,就会产生这种谬误,例如:
var obj = x; //VM112:1 Uncaught ReferenceError: x is not defined(…)
在 x 未声明的状况下抛出 ReferenceError
至于 SyntaxError,当咱们把语法错误的 JavaScript 字符串传入 eval() 函数时,就会导致此类谬误,例如:
eval('a ++ b'); //VM114:1 Uncaught SyntaxError: Unexpected identifier(…)
如果语法错误的代码呈现在 eval() 函数之外,则不太可能产生 SyntaxError,因为此时的语法错误导致 JavaScript 代码立刻进行执行。
TypeError 类型在 JavaScript 中常常用到,在变量中保留着意外的类型时,或者在拜访不存在的办法时,都会导致这种谬误。谬误的起因尽管多种多样,但归根结底还是因为在执行特定于类型的操作时,变量的类型并不符合要求所致。上面来看几个例子:
最常产生类型谬误的状况,就是传递给函数的参数当时未经查看,后果传入类型与预期类型不相符。
在应用 encodeURI() 或 decodeURI(),而 URI 格局不正确时,就会导致 URIError 谬误,这种谬误也很少见,因为后面说的这两个函数的容错性十分高。
利用不同的谬误类型,能够相熟更多无关异样的信息,从而有助于对谬误作出失当的解决,要想晓得谬误的类型,能够像上面这样在 try-catch 语句的 catch 语句中应用 instanceof 操作符:
try {someFunction();
} catch (error) {if (error instanceof TypeError) {// 解决类型谬误} else if (error instanceof ReferenceError) {// 解决援用谬误} else {// 解决其余类型的谬误}
}
在跨浏览器编程中,查看谬误类型是确定解决形式的最简便路径,蕴含在 message 属性中的谬误音讯会因浏览器而异。
- 善用 try-catch
当 try-catch 语句中产生谬误时,浏览器会认为谬误曾经被解决了。因此不会通过后面探讨的机制记录或报告谬误。对于那些不要求用户懂技术,也不须要用户了解谬误的 Web 应用程序,这应该说是个现实的后果。不过,try-catch 可能让咱们实现本人的错误处理机制。
应用 try-catch 最适宜解决那些咱们无法控制的谬误,假如你在应用一个大型的 JavaScript 库中的函数,该函数可能会有意无意地抛出一些谬误。因为咱们不能批改这个库的源代码,所以大可将对该函数的调用放在 try-catch 语句当中。万一有什么谬误产生,也好失当地解决它们。
在明明白白地晓得本人的代码会产生谬误时,再应用 try-catch 语句就不太适合了。例如,如果传递给函数的参数是字符串而非数值,就会造成函数出错,那么就应该先查看函数的类型,而后再决定如果去做。在这种状况下,不应该应用 try-catch 语句。
- try-catch 语句执行程序
看上面的例子:
执行程序为:首先执行 try 语句块中的代码,如果抛出异样,接着执行 catch 语句块中代码,如果没有异样,catch 语句块中代码将会被疏忽,但不论是否有异样,最初最会执行 finally 子句。try 前面必须接着一个 catch 或者 finally,也就是说 JavaScript 中的 try-catch 能够有 3 中组合模式。即 try-catch、try-finally、try-catch-finally 三种模式。
try-catch 个别的利用场景大家都比拟相熟,上面来看几个嵌套的例子:
下面这个例子中,最内部的 try 语句块中嵌套了一个 try-finally 语句,外部的 try 语句中抛出了一个异样,然而外部没有 catch 语句块,所以会执行最近的一个 catch 语句块,然而在跳出内部 try 蕴含语句块之前,须要先执行外部的 finally 语句块中的代码,所以最初的后果如上图所示。再看一个例子:
这个例子中,外部嵌套的语句块中有 catch 语句,所以当外部 try 语句块中抛出异样时,会接着执行外部的 catch 语句块,而后执行 finally 子句。因为异样曾经在外部解决实现,所以内部的 catch 语句块会被疏忽,所以最终后果如上所示。再看一个例子:
这个例子在下面例子的根底上,外部的 catch 语句块中又抛出了一个异样,所以,在执行完相应语句后,会接着执行内部的 catch 语句,后果如上所示。
二, 抛出谬误
与 try-catch 语句相配的还有一个 throw 操作符,用于随时抛出自定义谬误。抛出谬误时,必须要给 throw 操作符指定一个值。这个值是什么类型,没有要求。下列代码都是无效的。
throw 12345;
throw 'Hello world!';
throw true;
throw {name: 'JavaScript'};
在遇到 throw 操作符时,代码会立刻进行执行。仅当有 try-catch 语句捕捉到被抛出的值时,代码才会继续执行。
通过应用某种内置谬误类型,能够更实在地模仿浏览器谬误。每种谬误类型的构造函数承受一个参数,即理论的错误信息。上面是一个例子:
throw new Error(‘Something bad happened.’);
这行代码抛出了一个通用谬误,带有一条自定义错误信息。浏览器会像解决本人生成的谬误一样,来解决这行代码抛出的谬误。换句话说,浏览器会以惯例形式报告这一谬误,并且会显示这里的自定义谬误类型。像上面应用其余谬误类型,也能够模拟出相似的浏览器谬误:
throw new SyntaxError("I don't like your syntax.");
throw new TypeError("what type of variable do you take me for?");
throw new RangeError("Sorry, you just don't have the range.");
throw new EvalError("That doesn't evaluate.");
throw new URIError("Uri, is that you?");
throw new ReferenceError("You didn't cite your references properly.");
在创立自定义谬误音讯时,最罕用的谬误类型是 Error、RangeError、ReferenceError 和 TypeError。另外,利用原型链还能够通过继承 Error 来创立自定义谬误类型。此时,须要为新创建的谬误类型指定 name 和 message 属性。来看一个例子:
浏览器看待继承自 Error 的自定义谬误类型,就像看待其余谬误类型一样。如果要捕捉本人抛出的谬误并且把它与浏览器谬误区别对待的话,创立自定义谬误是很有用的。(IE 只有在抛出 Error 对象的时候才会显示自定义错误信息。对于其余类型,它都无一例外地显示 ”exception thrown and not caught”(抛出了异样,且未被捕捉))。
冰冻三尺 , 非一日之寒,
学好编程 , 非一年之功.
坚持不懈 , 苦练勤钻研,
年薪百万 , 翘首笑开颜.