JavaScript 控制流与错误处理
原创控制流与错误处理
JavaScript 提供了一套精简的语句,特别是控制流语句,使开发者能够在应用程序中实现丰富的交互功能。本章将概述这些重要的控制结构和错误处理机制。
JavaScript 代码中,分号(;)字符用于分隔不同的语句。有关更详细的语句信息,请参阅JavaScript 参考。值得注意的是,JavaScript 表达式本身也是语句,更多关于表达式的内容可参考表达式与运算符。
块语句
最基础的语句是用于组合多个语句的块语句,它由一对花括号界定:
{
statement1;
statement2;
// …
statementN;
}
块语句通常用于控制流语句(如 if、for、while)中。例如:
while (x < 10) {
x++;
}
这里,{ x++; } 就是一个块语句。
需要注意的是,使用 var 声明的变量不是块级作用域的,而是函数作用域或脚本作用域的,其效果会延伸到块本身之外。例如:
var x = 1;
{
var x = 2;
}
console.log(x); // 输出 2
会输出 2,因为块中的 var x 与块前的 var x 作用域相同。(在 C 或 Java 中,等效代码会输出 1。)使用 let 或 const 可以消除这种作用域效果。
条件语句
条件语句是一组在指定条件为真时执行的指令。JavaScript 支持两种主要的条件语句:if...else 和 switch。
if...else 语句
if 语句用于在逻辑条件为 true 时执行语句,而可选的 else 子句则在条件为 false 时执行语句:
if (condition) {
statement1;
} else {
statement2;
}
其中 condition 可以是任何求值为 true 或 false 的表达式。如果条件为真,执行 statement1;否则执行 statement2。这些语句可以是任何内容,包括嵌套的 if 语句。
你也可以使用 else if 组合来按顺序测试多个条件:
if (condition1) {
statement1;
} else if (condition2) {
statement2;
} else if (conditionN) {
statementN;
} else {
statementLast;
}
在多个条件的情况下,只有第一个求值为 true 的条件对应的语句才会被执行。要执行多个语句,应将它们组合在一个块语句中({ /* ... */ })。
最佳实践
通常情况下,总是使用块语句是最佳实践,特别是在嵌套 if 语句时:
if (condition) {
// condition 为真时的语句
// …
} else {
// condition 为假时的语句
// …
}
一般而言,最好不要将赋值(如 x = y)作为 if...else 的条件,因为这容易导致逻辑错误。
假值
以下值在条件语句中求值为 false(也称为假值):
falseundefinednull0NaN- 空字符串(
"")
所有其他值——包括所有对象——在传递给条件语句时都会求值为 true。
switch 语句
switch 语句允许程序计算一个表达式的值,并将其与 case 标签进行匹配。如果匹配成功,程序会执行相关语句:
switch (expression) {
case label1:
statements1;
break;
case label2:
statements2;
break;
// …
default:
statementsDefault;
}
JavaScript 执行 switch 语句的过程如下:
- 程序首先查找与表达式值匹配的
case子句标签,然后将控制权转移到该子句,执行相关语句。 - 如果没有匹配的标签,程序会查找可选的
default子句:- 如果找到
default子句,程序将控制权转移到该子句,执行相关语句。 - 如果没有找到
default子句,程序继续执行 switch 语句后面的语句。
- 如果找到
break 语句
每个 case 子句可以关联一个可选的 break 语句,确保在匹配语句执行后程序能跳出 switch 结构,继续执行后续语句。如果忽略 break,程序将继续执行 switch 语句内的下一条 case 语句。
异常处理语句
JavaScript 提供了异常处理机制,可以使用 throw 语句抛出异常,并用 try...catch 语句捕获和处理这些异常。
异常类型
JavaScript 可以抛出任意对象作为异常。虽然抛出数字或字符串作为错误信息很常见,但使用专门为错误处理设计的异常类型通常更高效:
throw 语句
使用 throw 语句抛出异常,它会指定要抛出的值:
throw expression;
可以抛出任意类型的表达式,例如:
throw "错误 2"; // 字符串类型
throw 42; // 数字类型
throw true; // 布尔类型
throw {
toString() {
return "我是一个对象";
},
};
try...catch 语句
try...catch 语句用于标记一段可能抛出异常的代码块,并指定异常发生时的处理方式。如果抛出异常,try...catch 会捕获它。
try...catch 语句由 try 块(包含一个或多个可能抛出异常的语句)和 catch 块(包含异常发生时要执行的语句)组成。
如果 try 块中的语句抛出异常,控制权会立即转移到 catch 块。如果 try 块没有抛出异常,catch 块会被跳过。finally 块会在 try 和 catch 块执行之后、try...catch 后面的代码之前执行,无论是否抛出异常。
示例:
function getMonthName(mo) {
mo--; // 将月份调整为数组索引(0 = 一月,11 = 十二月)
const months = [
"一月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "十一月", "十二月",
];
if (months[mo]) {
return months[mo];
} else {
throw new Error("无效的月份数值");
}
}
try {
monthName = getMonthName(myMonth); // 可能抛出异常的函数
} catch (e) {
monthName = "未知";
logMyErrors(e); // 将异常对象传递给错误处理器
}
catch 块
catch 块用于处理 try 块中可能产生的所有异常:
catch (exception) {
statements
}
catch 块指定的标识符会存储由 throw 语句指定的值,可用于获取异常信息。该标识符只在 catch 块执行期间存在。
finally 块
finally 块包含的语句在 try 和 catch 块执行之后、try...catch...finally 语句后面的代码之前执行。无论是否抛出异常,finally 块都会执行。
可以使用 finally 块确保在异常发生时资源被正确释放。例如:
openMyFile();
try {
writeMyFile(theData); // 这可能会抛出错误
} catch (e) {
handleError(e); // 如果错误出现,处理它
} finally {
closeMyFile(); // 总是关闭资源
}
如果 finally 块返回一个值,该值将覆盖 try 和 catch 块中的任何 return 语句:
function f() {
try {
console.log(0);
throw "bogus";
} catch (e) {
console.log(1);
return true;
} finally {
console.log(3);
return false; // 覆盖前面的 return
}
}
console.log(f()); // 输出 0、1、3、false
使用 Error 对象
根据错误类型,可以使用 name 和 message 属性获取更精确的信息。在抛出自定义异常时,建议使用 Error 构造函数,这样可以充分利用这些属性:
function doSomethingErrorProne() {
if (ourCodeMakesAMistake()) {
throw new Error("消息");
} else {
doSomethingToGetAJavaScriptError();
}
}
try {
doSomethingErrorProne();
} catch (e) {
console.error(e.name); // 'Error'
console.error(e.message); // "消息"或JavaScript错误消息
}
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权本站发表,未经许可,不得转载。
开发学习网



