当程序执行过程中发生意外错误时,会抛出一个异常来确定应该针对该错误采取什么操作,但是如果异常本来可以提前抛出,您可以通过编程方式描述如何处理它。在这里,我将解释如何描述如何在 JavaScript 中处理异常。
目录
17-1 使用 try…catch 语句的异常处理
17-2 使用 try…catch…finally 语句进行异常处理
17-3 如果在 try 块中调用的函数中发生异常
17-4 捕获异常时根据异常类型单独处理
17-5 使用 throw 语句抛出异常
如果程序出现错误抛出异常,如果没有设置异常处理,程序会在此时被强制终止。使用 try…catch 语句来处理异常而不在抛出异常时中止。本节说明如何使用 try…catch 语句描述异常处理。
抛出异常时的行为
首先,让我们检查在不包含任何异常处理的程序中抛出异常时的行为。看看下面的示例。
function sum(a, b){
let sum = a + b;
return sum;
}
console.log('Start');
let result = sum(10, 8);
console.log(result);
console.log('End');
>> Start
>> 18
>> End
下面是一个使用简单函数的示例,该函数接受两个参数并返回它们的和。如果在调用函数时为两者指定数值,则不会发生错误。
让我们稍微改变一下示例,将调用函数时的参数之一更改为长整型值。
function sum(a, b){
let sum = a + b;
return sum;
}
console.log('Start');
let result = sum(10, 8n);
console.log(result);
console.log('End');
>> Start
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
这次在程序中间出现了TypeError。这是因为不能对数字和长整数值进行操作。程序运行过程中出现错误时抛出异常。如果没有编写代码来捕捉抛出的异常并进行适当的处理,程序将过早终止,如本例所示。
try…catch 语句用于捕获异常并采取适当的操作。在此之后,我将解释如何使用它。
如何使用 try…catch 语句
try…catch 语句允许您捕获抛出的异常并描述要做什么。格式如下。
try{
编写可以引发异常的语句
・・・
} catch(e) {
捕获到异常时怎么办
・・・
}
在 try 之后的块中编写可以引发异常的语句。仅捕获在此块内完成的处理抛出的异常。当发生错误并抛出异常时,依次执行catch之后的block中的处理。
catch后括号中写的变量e(变量名任意)存放异常抛出时设置的值。通常它是一个 Error 对象,但是如果你自己抛出异常,你可以指定任何值,所以它并不总是一个 Error 对象。
让我们修改前面的示例并使用 try…catch 语句添加异常处理。
function sum(a, b){
let sum;
try{
sum = a + b;
} catch(e) {
console.error(e);
return null;
}
return sum;
}
console.log('Start');
console.log(sum(10, 8));
console.log(sum(10, 8n));
console.log('End');
>> Start
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> null
>> End
在 try 块中编写一条语句,将变量添加到函数中。如果此语句抛出异常,现在您可以捕获异常。并且它描述了在catch块中捕获到异常时将执行的处理。这一次,将Error对象的内容输出到控制台后,将null返回给函数的调用者。
在本示例中,第一次调用函数时没有发生错误,因此进行了处理,使得没有 tyr…catch 语句。并且第二次调用该函数时,出现错误,也抛出异常,没有强制终止with,是运行到最后。
通过在描述异常处理时使用 try…catch…finally 语句,可以使用 finally 块来描述无论是否捕获到异常都将执行的操作。本节说明如何使用 try…catch…finally 语句描述异常处理。
使用 try…catch…finally 语句
try…catch…finally 语句允许您编写始终最后执行的操作,无论 try 块中是否抛出异常。格式如下。
try{
编写可以引发异常的语句
・・・
} catch(e) {
捕获到异常时怎么办
・・・
} finally {
最后行动
・・・
}
finally 之后的块总是在 try 块完成处理后执行,或者如果抛出异常则在 catch 块之后执行。在 try 或 catch 块内执行任何 retnrn、break 等语句之前执行,即使处理从 try…catch…finally 语句移开。将是
如果在try块中进行文件处理或数据库处理时,不管是否抛出异常,最后都想关闭文件连接或断开数据库连接,好像经常用到。
这是一个检查操作的简单示例。
function sum(a, b){
let sum;
try{
sum = a + b;
} catch(e) {
console.error(e);
return null;
} finally {
console.log('Finally!');
}
return sum;
}
console.log('Start');
console.log(sum(10, 8));
console.log(sum(10, 8n));
console.log('End');
>> Start
>> Finally!
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> Finally!
>> null
>> End
能抛出异常的语句写在try块中,捕获到异常时的处理写在catch块中。而 finally 块描述了无论是否捕获到异常都将在最后执行的处理。
在这个例子中,第一次调用该函数时没有发生任何错误,所以 tyr…catch…finally 语句就像什么都不存在一样处理。即使在这种情况下,finally 块内的处理也会执行。并且第二次调用该函数时,出现错误,也抛出异常,没有强制终止with,是运行到最后。而且即使捕获到异常,finally块中的处理也会执行。
没有catch的try…finally语句的格式是没有问题的。
try{
编写可以引发异常的语句
・・・
} finally {
最后行动
・・・
}
但是,如果没有catch,就无法捕捉到异常,所以如果抛出异常,程序就会被强行终止。
使用 try…catch 语句的异常处理捕获异常并在 try 块中编写的语句抛出异常时执行处理。即使异常发生在 . 但是,使用回调函数时要小心。本节说明如何处理在 try 块中调用的函数中发生的异常。
如果在 try 块中调用的函数中发生异常
try…catch语句的格式如下,可能导致异常的语句必须写在try之后的块中。
try{
编写可以引发异常的语句
・・・
} catch(e) {
捕获到异常时怎么办
・・・
}
那么如果 try 块在 try…catch 语句之外调用一个函数并且在该函数内部抛出异常会发生什么?
function func(){
// 这里出现异常
}
try{
func();
} catch(e) {
捕获到异常时怎么办
・・・
}
即使在这种情况下,也与在 try 块中抛出异常时一样捕获异常,并执行 catch 之后的块中的处理。
看看下面的示例。
function sum(a, b){
let sum;
sum = a + b;
return sum;
}
console.log('Start');
try{
console.log(sum(10, 8));
console.log(sum(10, 8n));
} catch(e) {
console.error(e);
}
console.log('End');
>> Start
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> End
在这个示例中,调用函数的语句写在try块中,而不是将可能产生异常的函数写在try块中。被调用的函数没有写在 try 块中,但即使在这种情况下,函数抛出的异常也可以被函数的调用者捕获和处理。
请看另一个例子。
function sumB(a, b){
let sum;
sum = a + b;
return sum;
}
function sumA(a, b){
return sumB(a, b);
}
console.log('Start');
try{
console.log(sumA(10, 8));
console.log(sumA(10, 8n));
} catch(e) {
console.error(e);
}
console.log('End');
>> Start
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> End
我们稍微修改了前面的示例并在两者之间放置了另一个函数。即使在这种情况下,最终调用的函数中抛出的异常也会追溯到调用者,如果在某个时候可以使用 try…catch 语句捕获异常,则会处理该异常。可以做。
异步处理回调函数出现异常时
我之前解释过,调用函数中发生的异常可以被函数的调用者捕获,但有一些注意事项。重点是无法捕获执行异步处理的回调函数中发生的异常。
看看下面的示例。这是一个简单的程序,在指定时间过去后使用 setTimeout 函数调用指定为参数的回调函数。
console.log('Start');
setTimeout(function sum(a, b){
let sum = a + b;
console.log(sum);
},1000, 10, 8);
console.log('End');
>> Start
>> End
>> 18
由于 setTimeout 函数的第二个参数指定了 1000 毫秒(1 秒),因此从 setTimeout 方法执行 1 秒后调用第一个参数指定的回调函数,并将运行结果显示在控制台输出.
由于这个回调函数可能会出现异常,所以将setTimeout函数的部分写在try块中,并将传递给回调函数的参数值改为几天和一个长整型。增加。
console.log('Start');
try{
setTimeout(function sum(a, b){
let sum = a + b;
console.log(sum);
},1000, 10, 8n);
} catch(e) {
console.error('异常被捕获);
}
console.log('End');
>> Start
>> End
>> Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
我在运行这个示例时,回调函数中发生的异常无法被try…catch语句捕获,错误输出到控制台,程序被强行终止。这是因为回调函数在 try 块内部,但您是从 try 块外部调用回调函数。
请注意,在像这样的异步处理中使用回调函数时,无法捕获回调函数内发生的异常。
有几种类型的错误会导致抛出异常。如果在使用try…catch 语句的异常处理中可能会出现多种类型的异常,则可以通过为抛出的每种类型的异常编写多个catch 来分离要执行的处理。在这里,我将说明在使用try…catch语句捕获异常时,如何根据异常类型来划分处理。
引发异常的错误类型
例外が発生するエラーの種類として次の 8 種類がグローバルオブジェクトとして定義されています。
Error 一般错误
EvalError 与eval函数相关的错误
InternalError JavaScript内部错误
RangeError 数字超出有效范围时的错误
ReferenceError 无效引用时的错误
SyntaxError JavaScript语法错误
TypeError 变量或参数类型错误时的错误
URIError encodeURI或decodeURI 错误
不过SyntaxError不是运行时的错误,而是执行前的错误,所以除非你显式创建一个SyntaxError对象并抛出,否则不会因为语法错误而在运行时抛出异常。我认为。
例如,Number 对象的 toString 方法只接受 2 到 36 范围内的值作为参数,但如果指定了超出该范围的值,则会发生 RangeError。
let num = 10;
console.log(num.toString(100));
>> RangeError: toString() radix argument must be between 2 and 36
此外,即使在同一过程中也可能出现多种类型的错误。Number 对象的 toFixed 方法只接受 0 到 100 范围内的值作为参数,但如果值超出该范围,则会引发 RangeError。此外,在非数字值上调用此方法将引发 TypeError。此外,在不带括号的整数数字文字上调用此方法将引发 SyntaxError。
let num = 3.14;
console.log(num.toFixed(1000));
>> RangeError: toFixed() digits argument must be between 0 and 100
let str = '3.14';
console.log(str.toFixed());
>> TypeError: str.toFixed is not a function
console.log(24.toFixed());
>> SyntaxError: Invalid or unexpected token
try…catch 语句可以捕获抛出的任何类型的异常,但它也可以处理捕获的不同类型的异常。
根据异常类型分离要执行的处理
如果想不管异常的类型都做同样的处理,写成如下。
function returnFixed(num, digits){
try{
return num.toFixed(digits)
} catch(e) {
console.error(e);
return null;
}
}
console.log('Start');
console.log(returnFixed(3.87654, 3));
console.log(returnFixed(3.87654, 1000));
console.log(returnFixed('3.87654', 1000));
console.log('End');
>> Start
>> 3.877
>> RangeError: toFixed() digits argument must be between 0 and 100
>> null
>> TypeError: num.toFixed is not a function
>> null
>> End
在此示例中,调用了带有 try…catch 语句的外部函数三次。第一次返回成功结果,但是第二次和第三次都抛出异常。第二次和第三次发生的异常类型不同,但在同一个catch块中进行了相同的处理。
如果要对发生的每种类型的异常分别执行处理,请在 catch 之后检查括号中描述的变量 e 中存储的值并执行条件分支。
try{
例外が発生する可能性がある文を記述
・・・
} catch(e) {
if (e instanceof RangeError){
// RangeError 如果发生 RangeError怎么办
・・・
} else if (e instanceof TypeError){
// TypeError 如果引发 TypeError怎么办
・・・
} else {
// 发生上述以外的异常时执行的处理
・・・
}
}
catch 之后的变量包含抛出异常时设置的值。您可以通过使用 instanceof 运算符将此值与 RangeError 或 TypeError 对象进行比较来确定异常的类型。
现在,让我们改变之前的示例,以便对每种类型的异常执行不同的处理。
function returnFixed(num, digits){
try{
return num.toFixed(digits)
} catch(e) {
if (e instanceof RangeError){
console.error('RangeError');
return null;
} else if (e instanceof TypeError){
console.error('TypeError');
return null;
} else {
console.error(e);
return null;
}
}
}
console.log('Start');
console.log(returnFixed(3.87654, 3));
console.log(returnFixed(3.87654, 1000));
console.log(returnFixed('3.87654', 1000));
console.log('End');
>> Start
>> 3.877
>> RangeError
>> null
>> TypeError
>> null
>> End
更改为根据发生的异常类型执行不同的处理。
当程序执行过程中出现错误时就会抛出异常,但你可以随时使用throw语句抛出异常。本节介绍如何使用 throw 语句抛出异常。
throw如何使用抛出语句
可以使用 throw 语句抛出异常。格式如下。
throw 异常值
异常值通常是一个 Error 对象,但也可以是任何值,例如数字或字符串。当使用 try…catch 语句捕获异常时,此处指定的异常值将存储在 catch 括号内写入的变量中。
看看下面的示例。
function checkResult(point){
try{
if (point < 50){
throw '失败';
}
console.log('分数' + point);
console.log('通过');
} catch(e) {
console.error(e);
}
}
console.log('Start');
console.log(checkResult(82));
console.log(checkResult(40));
console.log('End');
>> Start
>> 得分82
>> 通过
>> 失败
>> End
在此示例中,我们检查函数中作为参数传递的值,如果小于 50 则抛出异常。这次我们指定一个字符串作为异常值。抛出的异常由 try…catch 语句捕获,并执行 catch 块内描述的处理。