2、JavaScript控制流和错误处理

目录

  • [1. 块语句](#1. 块语句)
  • [2. 条件语句](#2. 条件语句)
    • [2.1 if ... else语句](#2.1 if ... else语句)
      • [2.1.1 假植](#2.1.1 假植)
    • [2.2 switch语句](#2.2 switch语句)
      • [2.2.1 break语句](#2.2.1 break语句)
  • [3. 异常处理语句](#3. 异常处理语句)
    • [3.1 异常类型](#3.1 异常类型)
    • [3.2 throw语句](#3.2 throw语句)
    • [3.3 try...catch语句](#3.3 try...catch语句)
      • [3.3.1 catch块](#3.3.1 catch块)
      • [3.3.2 finally块](#3.3.2 finally块)
      • [3.3.3 嵌套的try...catch语句](#3.3.3 嵌套的try...catch语句)
    • [3.4 使用Error对象](#3.4 使用Error对象)
  • 参考
  • 待了解

1. 块语句

  最基本的块语句是用于组合语句的块语句。块由一对花括号界定:

javascript 复制代码
{
	statement1;
	statement2;
	// ...
	statementN;
}

  例子:

javascript 复制代码
while (x < 10) {
	x++;
}

  { x++; }是块语句。

  注意:用var声明的变量不是块作用域,而是函数作用域或脚本作用域,且设置它们的效果会超越到块本身之外。

javascript 复制代码
var x = 1;
console.log(x); // 打印 1
{
	var x = 2;
}
console.log(x); // 打印 2

块中var x语句和块前面var x语句的作用域是一样的。使用let或const来声明块作用域的变量。

2. 条件语句

  条件语句是一组会在指定的条件为真时执行的指令,支持两种条件语句:if ... else和switch。

2.1 if ... else语句

  使用if语句在逻辑条件为true时执行语句。使用可选的else子句在条件为false时执行语句。

javascript 复制代码
if (condition) {
	statement1;
} else {
	statement2;
}

  可以使用else if组合语句按顺序测试多个条件:

javascript 复制代码
if (condition1) {
	statement1;
} else if (condition2) {
	statement2;
} else if (conditionN) {
	statementN;
} else {
	statementLast;
}

  一般而言,最好不要将赋值作为if ... else的条件:

javascript 复制代码
if (x = y) {
	// 在这里添加语句
}

2.1.1 假植

  下面这些值求值为false:

  1、false。

  2、undefined。

  3、null。

  4、0。

  5、NaN

  6、空字符串""。

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

  注意:不要混淆原始布尔值true和false与Boolean对象的真和假!

javascript 复制代码
const b = new Boolean(false);
if (b) {
	// 这个条件求值为true
}
if (b == true) {
	// 这个条件求值为false
}

2.2 switch语句

  switch语句允许程序求一个表达式的值并且尝试将表达式的值和case标签进行匹配。如果匹配成功,程序会执行相关的语句。

javascript 复制代码
switch (expression) {
	case label1:
		statements1;
		break;
	case label2:
		statements2;
		break;
	// ...
	default:
		statementsDefault;
}

  JavaScript求值上面的switch语句的过程如下:

  1. 程序首先查找一个与expression的值匹配的case子句标签,然后将控制权转移到该子句,执行相关的语句。

  2. 如果没有匹配的标签,程序会去找可选的default子句:

    如果找到了default子句,程序会将控制权转移到该子句,执行相关的语句。

    如果没有找到default子句,程序会继续执行switch语句后面的语句。

    default子句通常是最后一个子句,当然这不是必须的。

2.2.1 break语句

  每个case子句会关联一个可选的break语句,它能保证在匹配的语句被执行后程序可以跳出switch并且继续执行switch后面的语句。如果break被忽略,程序会在switch语句内继续执行,将会执行下一个case的语句,依次类推。

javascript 复制代码
let fruitType = "Apples";
switch (fruitType) {
	case "Oranges":
		console.log("橙子是$0.59 一磅");
		break;
	case "Apples":
		console.log("苹果是$0.32 一磅");
		break;
	case "Bananas":
		console.log("香蕉是$0.48 一磅");
		break;
	case "Cherries":
		console.log("樱桃是$3.00 一磅");
		break;
	default:
		console.log(`对不起,${fruitType}卖完了。`);
}
console.log("还有其他什么是你喜欢的吗?");

3. 异常处理语句

  可以用throw语句抛出一个异常并且用try...catch语句处理它。

3.1 异常类型

  JavaScript可以抛出任何对象。然而,并非所有抛出的对象都是生而平等的。尽管抛出数字或者字符串作为错误信息十分常见,但是用下列其中一种专门为这个目的而创建的异常类型通常更为高效:

  1. ECMAScript异常。

  2. DOMException。

3.2 throw语句

  使用throw语句抛出异常。throw语句会指明要抛出的值。

javascript 复制代码
throw "错误 2"; // 字符串类型
throw 42; //数字类型
throw true; // 布尔类型
throw {
	toString() {
		return "我是一个对象";
	},
}; 

3.3 try...catch语句

  try...catch语句用于标记一段要尝试的语句块,并指定抛出异常时的一个或多个响应。如果抛出了异常,try...catch语句会捕获它。

  try...catch语句由try块(其包含一个或多个语句)和catch(其包含在try块中抛出异常时要执行的语句)块组成。

  换句话说,你希望try块执行成功------但如果它没有执行成功,那么你希望将控制转移到catch块。如果try块中的语句抛出了异常,那么控制立马转移到catch块中。如果try块没有抛出异常,catch块就会被跳过。finally块总会紧跟在try和catch块之后执行,但会在try...catch语句后面的语句之前执行。

javascript 复制代码
function getMonthName(mo) {
	mo--; // 将月份调整为数组索引
	const months = [
		"一月", "二月", "三月", "四月", "五月", "六月",
		"七月", "八月", "九月", "十月", "十一月", "十二月",
	];
	if (months[mo]) {
		return months[mo];
	} else {
		throw new Error("无效的月份数值");
	}
}

try {
	let myMonth = 13;
	let monthName = getMonthName(myMonth);
} catch(e) {
	let monthName = "未知";
	console.error(e);
}

3.3.1 catch块

  可以使用catch块来处理所有可能在try块中产生的异常:

javascript 复制代码
catch (exception) {
	statements;
}

  catch块指定的标识符会存储由throw语句指定的值。可以用这个标识符来获取抛出的异常的信息。在进入catch块时JavaScript会创建这个标识符。标识符只存在于catch块的存续期间里。当catch块执行完成时,标识符不再可用。

  在catch块中将错误输出到控制台时,建议使用console.error()而不是console.log()进行调试。它会将消息格式化为错误,并将其添加到页面生成的错误消息列表中。

3.3.2 finally块

  finally块包含的语句在try和catch块执行之后执行。此外,finally块在try...catch...finally语句后面的代码之前执行。

  finally块无论是否抛出异常都会执行。如果抛出了一个异常,就算没有catch块处理抛出的异常,finally块里的语句也会执行。可以用finally块来令你的脚本在异常发生时优雅地退出。

  如果finally块返回一个值,该值会是整个try...catch...finally流程的返回值,不管try和catch块中的return语句返回了什么:

javascript 复制代码
function f() {
	try {
		console.log(0);
		throw "bogus";
	} catch (e) {
		console.log(1);
		// 这个return语句会被挂起直到finally块结束
		return true;
		console.log(2); // 不可达
	} finally {
		console.log(3);
		return false; // 覆盖前面的"return"
		console.log(4); // 不可达
	}
	// 执行return false
	console.log(5); // 不可达
}
console.log(f()); // 0、1、3、false

  用finally块覆盖返回值也适用于在catch块内抛出或重新抛出的异常:

javascript 复制代码
function f() {
	try {
		throw "bogus";
	} catch (e) {
		console.log("捕获内部的"bogus"");
		// 这个return语句会被挂起直到finally块结束
		throw e;
	} finally {
		return false; // 覆盖前面的throw
	}
	// 现在执行return false
}

try {
	console.log(f());
} catch (e) {
	// 永远不会抵达
	// f()执行时,`finally`块返回false,而这会覆盖上面的`catch`中的`throw`
	console.log("捕获外部的"bogus"");
}
// 日志:
// 捕获内部的"bogus"
// false

3.3.3 嵌套的try...catch语句

  可以嵌套一个或多个try...catch语句。

  如果一个内部try块没有对应的catch块:它必须有一个finally块,以及包围的try...catch语句的catch块会被检查是否能处理该异常。

3.4 使用Error对象

  根据错误类型,你也许可以用name和message属性获取更精炼的信息。name属性提供了常规的Error类,如DOMException或Error,而Message通常提供的信息比将错误对象转换成字符串得到的信息更简明。

  在抛出自定义异常时,为了充分利用那些属性,比如catch块不能分辨是自定义异常还是系统异常时,你可以使用Error构造函数。

javascript 复制代码
function ourCodeMakesAMistake() { return true; }  // 返回 true 触发 throw
function doSomethingToGetAJavaScriptError() { 
  nonExistentFunction(); // 这会抛出 ReferenceError(如果执行到的话)
}

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

try {
  doSomethingErrorProne();
} catch (e) {
  console.error(e.name);    // 输出 "Error"
  console.error(e.message); // 输出 "消息"
}

参考

1、控制流与错误处理

待了解

1、ECMAScript异常

2、DOMException

3、嵌套try块

相关推荐
晓得迷路了1 小时前
栗子前端技术周刊第 142 期 - DeepSeek Harness、pnpm 12 RC、crypto‑js...
前端·javascript·ai编程
Fluxart.ai1 小时前
Etsy手工制品换背景,用什么AI能保留手作质感?
前端·javascript·人工智能
小玮看世界1 小时前
[Python] str() 和 join() 的区别与实战避坑指南
前端·javascript·python
谢慧琼14 小时前
2026零基础做企业网站,低成本搭建官方网站
服务器·前端·javascript
拾年27516 小时前
React Hooks 进阶篇:useMemo / useCallback / useReducer / useImperativeHandle,用「算账 +
前端·javascript·react.js
Jackson__17 小时前
面试官:如何在老项目中使用新框架,并实现通信?
前端·javascript·面试
拾年27517 小时前
React Hooks 保姆级教程:把组件想象成失忆的打工人,4 个 Hook 带你原地起飞
前端·javascript·react.js
默_笙17 小时前
😝 5 亿次循环卡死页面?我用 Web Worker 把它扔进后台线程,页面丝滑如初
前端·javascript