JS错误处理 – JavaScript高级教程

上一章JavaScript教程请查看:JS JSON转换
在本教程中,我们将学习如何在JavaScript中优雅地处理错误。
处理错误有时你的JavaScript代码不能像预期的那样流畅地运行,从而导致错误。可能导致错误的原因有很多,例如:

  • 网络连接问题
  • 用户可能在表单字段中输入了无效的值
  • 引用不存在的对象或函数
  • 从web服务器发送或接收的数据不正确
  • 应用程序需要访问的服务可能暂时不可用
这些类型的错误称为运行时错误,因为它们发生在脚本运行时。一个专业的应用程序必须有能力优雅地处理这种运行时错误。通常这意味着更清楚、更准确地告知用户问题。
try… catch语句JavaScript提供try-catch语句来捕获运行时错误,并优雅地处理它们。
任何可能抛出错误的代码都应该放在语句的try块中,处理错误的代码放在catch块中,如下所示:
try { // 可能导致错误的代码 } catch(error) { // 发生错误时要执行的操作 }

如果try块中的任何点发生错误,则代码执行立即从try块转移到catch块。如果try块中没有发生错误,catch块将被忽略,程序将在try-catch语句之后继续执行。
下面的例子演示了try-catch语句是如何工作的:
try { var greet = "Hi, there!"; document.write(greet); // 试图访问一个不存在的变量 document.write(welcome); // 如果发生错误,以下行将不执行 alert("所有语句都成功执行."); } catch(error) { // 处理错误 alert("发现错误: " + error.message); } // 继续执行 document.write("< p>Hello World!< /p>");

上面的脚本将生成一个错误,并显示在一个警告对话框中,而不是将其打印到浏览器控制台。此外,即使发生了错误,程序也不会突然停止。
另外,请注意catch关键字后面是一个括号中的标识符。此标识符的作用类似于函数参数。当发生错误时,JavaScript解释器会生成一个对象,该对象包含有关错误的详细信息。然后将此错误对象作为要捕获catch的参数传递以进行处理。
提示:try-catch语句是一种异常处理机制。异常是指示在程序执行过程中发生了某种异常条件或错误的信号。术语“异常”和“错误”经常交替使用。
try… catch… finally语句try-catch语句也可以有一个finally子句,无论try块中是否发生了错误,finally块中的代码都将始终执行。
【JS错误处理 – JavaScript高级教程】下面的示例将始终显示完成代码执行所需的总时间。
// 将提示对话框返回的值赋给一个变量 var num = prompt("输入0到100之间的正整数"); // 存储执行开始的时间 var start = Date.now(); try { if(num > 0 & & num < = 100) { alert(Math.pow(num, num)); } else { throw new Error("输入了无效的值!"); } } catch(e) { alert(e.message); } finally { // 显示执行代码所需的时间 alert("执行了: " + (Date.now() - start) + "ms");

抛出错误到目前为止,我们已经看到了JavaScript解析器在发生错误时自动抛出的错误。但是,也可以使用throw语句手动抛出错误。
抛出throw语句的一般形式(或语法)是:throw expression;
表达式expression可以是任何数据类型的对象或值。但是,最好使用对象,最好使用名称和消息属性。JavaScript内置的Error()构造函数提供了一种创建错误对象的方便方法。让我们来看一些例子:
throw 123; throw "缺失值!"; throw true; throw { name: "InvalidParameter", message: "参数不是一个数字!" }; throw new Error("出现错误!");

注意: 如果你使用JavaScript内置的错误构造函数(例如error()、TypeError()等)来创建错误对象,那么name属性与构造函数的名称相同,消息等于传递给构造函数的参数。
现在我们将创建一个函数squareRoot()来查找一个数的平方根。这可以通过使用JavaScript内置函数Math.sqrt()来实现,但是这里的问题是,它返回负数的NaN,而没有提供任何关于出错原因的提示。
我们将通过在提供负数时抛出自定义错误来修复这个问题。
function squareRoot(number) { // 如果数字是负数,抛出错误 if(number < 0) { throw new Error("抱歉,不能计算负数的平方根。"); } else { return Math.sqrt(number); } }try { squareRoot(16); squareRoot(625); squareRoot(-9); squareRoot(100); // 如果抛出错误,以下行将不执行 alert("所有计算都成功执行."); } catch(e) { // 处理错误 alert(e.message);

提示: 理论上可以使用虚数i来计算负数的平方根,其中i2 = -1,因此-4的平方根是2i, -9的平方根是3i,以此类推。但是JavaScript不支持虚数。
错误类型Error对象是所有错误的基本类型,它有两个主要属性——一个指定错误类型的name属性和一个保存详细描述错误的消息的message属性。任何抛出的错误都是错误对象的实例。
在JavaScript程序执行过程中可能发生几种不同类型的错误,比如RangeError、ReferenceError、SyntaxError、TypeError和URIError。
下面的小节将更详细地描述每种错误类型:
RangeError当使用超出允许值范围的数字时,将引发RangeError。例如,创建一个长度为负的数组将抛出RangeError。
var num = 12.735; num.toFixed(200); // 抛出范围错误(允许的范围从0到100)var array = new Array(-1); // 抛出范围错误

ReferenceError当你试图引用或访问一个不存在的变量或对象时,通常会抛出一个ReferenceError。下面的示例显示了ReferenceError是如何发生的。
console.log(firstname); // 抛出引用错误(变量名区分大小写)undefinedObj.getValues(); // 抛出引用错误nonexistentArray.length; // 抛出引用错误

SyntaxError如果JavaScript代码中存在语法问题,则在运行时抛出SyntaxError。例如,如果缺少右括号,循环的结构就不正确,等等。
var array = ["a", "b", "c"]; document.write(array.slice(2); // 抛出语法错误(缺少括号)alert("Hello World!'); // 抛出语法错误(引用不匹配)

TypeError当值不属于预期类型时,将引发类型错误。例如,对number调用字符串方法,对string调用数组方法,等等。
var num = 123; num.toLowerCase(); /* 抛出类型错误(因为toLowerCase()是一个字符串方法,数字不能转换为小写) */var greet = "Hello World!" greet.join() // 抛出类型错误(因为join()是一个数组方法)

URIError当你为URI相关的函数(如encodeURI()或decodeURI()指定一个无效的URI(代表统一资源标识符)时,会抛出一个URIError,如下所示:
var a = "%22%E9%63"; decodeURI(a); // 抛出URI错误var b = "\uF700"; encodeURI(b); // 抛出URI错误

注意: 还有一个错误类型EvalError,它是在通过eval()函数执行代码时发生错误时抛出的。但是,这个错误不再由JavaScript抛出,但是这个对象仍然保持向后兼容性。
特定的错误类型也可以使用它们各自的构造函数和抛出语句来手动抛出,例如,要抛出一个类型错误,可以使用TypeError()构造函数,如下所示:
var num = prompt("请输入一个数"); try { if(num != "" & & num !== null & & isFinite(+num)) { alert(Math.exp(num)); } else { throw new TypeError("没有输入数字."); } } catch(e) { alert(e.name); alert(e.message); alert(e.stack); // 非标准属性

注意:Error对象还支持一些非标准属性。最广泛使用的此类属性之一是:stack,它返回该错误的堆栈跟踪,你可以将其用于调试目的,但不要在生产站点上使用它。

    推荐阅读