JavaScript 控制流与错误处理

原创
admin 4个月前 (08-18) 阅读数 18 #JavaScript

控制流与错误处理

JavaScript 提供了一套精简的语句,特别是控制流语句,使开发者能够在应用程序中实现丰富的交互功能。本章将概述这些重要的控制结构和错误处理机制。

JavaScript 代码中,分号(;)字符用于分隔不同的语句。有关更详细的语句信息,请参阅JavaScript 参考。值得注意的是,JavaScript 表达式本身也是语句,更多关于表达式的内容可参考表达式与运算符

块语句

最基础的语句是用于组合多个语句的块语句,它由一对花括号界定:

{
  statement1;
  statement2;
  // …
  statementN;
}

块语句通常用于控制流语句(如 ifforwhile)中。例如:

while (x < 10) {
  x++;
}

这里,{ x++; } 就是一个块语句。

需要注意的是,使用 var 声明的变量不是块级作用域的,而是函数作用域或脚本作用域的,其效果会延伸到块本身之外。例如:

var x = 1;
{
  var x = 2;
}
console.log(x); // 输出 2

会输出 2,因为块中的 var x 与块前的 var x 作用域相同。(在 C 或 Java 中,等效代码会输出 1。)使用 letconst 可以消除这种作用域效果。

条件语句

条件语句是一组在指定条件为真时执行的指令。JavaScript 支持两种主要的条件语句:if...elseswitch

if...else 语句

if 语句用于在逻辑条件为 true 时执行语句,而可选的 else 子句则在条件为 false 时执行语句:

if (condition) {
  statement1;
} else {
  statement2;
}

其中 condition 可以是任何求值为 truefalse 的表达式。如果条件为真,执行 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(也称为假值):

  • false
  • undefined
  • null
  • 0
  • NaN
  • 空字符串(""

所有其他值——包括所有对象——在传递给条件语句时都会求值为 true

switch 语句

switch 语句允许程序计算一个表达式的值,并将其与 case 标签进行匹配。如果匹配成功,程序会执行相关语句:

switch (expression) {
  case label1:
    statements1;
    break;
  case label2:
    statements2;
    break;
  // …
  default:
    statementsDefault;
}

JavaScript 执行 switch 语句的过程如下:

  1. 程序首先查找与表达式值匹配的 case 子句标签,然后将控制权转移到该子句,执行相关语句。
  2. 如果没有匹配的标签,程序会查找可选的 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 块会在 trycatch 块执行之后、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 块包含的语句在 trycatch 块执行之后、try...catch...finally 语句后面的代码之前执行。无论是否抛出异常,finally 块都会执行。

可以使用 finally 块确保在异常发生时资源被正确释放。例如:

openMyFile();
try {
  writeMyFile(theData); // 这可能会抛出错误
} catch (e) {
  handleError(e); // 如果错误出现,处理它
} finally {
  closeMyFile(); // 总是关闭资源
}

如果 finally 块返回一个值,该值将覆盖 trycatch 块中的任何 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 对象

根据错误类型,可以使用 namemessage 属性获取更精确的信息。在抛出自定义异常时,建议使用 Error 构造函数,这样可以充分利用这些属性:

function doSomethingErrorProne() {
  if (ourCodeMakesAMistake()) {
    throw new Error("消息");
  } else {
    doSomethingToGetAJavaScriptError();
  }
}

try {
  doSomethingErrorProne();
} catch (e) {
  console.error(e.name); // 'Error'
  console.error(e.message); // "消息"或JavaScript错误消息
}
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权本站发表,未经许可,不得转载。

作者文章
热门
最新文章
标签列表