JavaScript学习笔记:3.控制流与错误处理

JavaScript学习笔记:3.控制流与错误处理

上一篇搞定了JS的“内功心法”(基础语法与数据类型),这一篇咱们来解锁JS的“实战技能”——控制流与错误处理。如果说变量和数据类型是JS的“砖瓦”,那控制流就是“建筑图纸”(决定代码执行顺序),错误处理就是“安全网”(防止代码崩掉)。今天就用接地气的例子,带你吃透这些核心知识点,从此写代码能“做对决策”,还能“从容兜底”~

一、块语句:给代码划清“独立空间”

块语句是JS里最基础的“代码容器”,用一对{}把多条语句包起来,就像给代码划了个“独立房间”。它通常和控制流语句(if、for、while)搭配使用,比如:

while (奶茶没喝完) {
  吸一口; // 这整个{}就是块语句
}

但这个“房间”对不同变量的“约束力”不一样——这就是新手最容易踩的坑!

避坑重点:var vs let/const的“房间规则”

  • var:串门的“邻居”:用var声明的变量不受块语句约束,会“串门”到函数或全局作用域。比如:

    var 奶茶 = "全糖";
    {
      var 奶茶 = "三分糖"; // 同一个变量,覆盖了外面的值
    }
    console.log(奶茶); // 输出“三分糖”——var直接“串门”改了全局变量
    

    这就像你在自己房间换了衣服,结果邻居的衣服也跟着变了,离谱!

  • let/const:安分守己的“住户”:用let或const声明的变量是“块级作用域”,只在自己的“房间”里生效,不会打扰外面:

    let 奶茶 = "全糖";
    {
      let 奶茶 = "三分糖"; // 独立的局部变量
    }
    console.log(奶茶); // 输出“全糖”——外面的变量不受影响
    

    这才是正常的“房间规则”!所以记住:块语句里优先用let/const,彻底和var说再见

二、条件语句:JS的“决策大脑”

条件语句让JS能“根据情况做选择”,就像你出门前看天气:下雨带伞,晴天戴帽。JS里有两种核心条件语句:if...elseswitch,各有擅长场景。

1. if…else:灵活的“多岔路口”

if...else就像人生的“岔路口”,满足条件走一条路,不满足走另一条。语法很简单:

if (条件A) {A;
} else if (条件B) {B;
} else {
  实在没路走,兜底方案;
}

但这里藏着两个“致命坑”,新手必栽!

坑1:假值的“伪装术”

JS里有6个“假值”,它们会被条件语句当成false处理,其余全是true

  • falseundefinednull
  • 0NaN
  • 空字符串""

举个反例,你以为能判断“用户输入了内容”,结果栽了:

const 用户名 = ""; // 用户没输入,是空字符串
if (用户名) {
  console.log("欢迎登录");
} else {
  console.log("请输入用户名"); // 正确执行,因为""是假值
}

// 坑!如果用户输入0:
const 年龄 = 0; // 0是合法年龄,但却是假值
if (年龄) {
  console.log("年龄合法");
} else {
  console.log("请输入合法年龄"); // 错误执行!
}

避坑指南:如果要判断“是否存在值”,别直接用if(变量),要用精准判断:

if (年龄 !== undefined && 年龄 !== null) { // 排除未定义和空值
  console.log("年龄合法");
}
坑2:条件里的“赋值陷阱”

千万别在if条件里写赋值语句(=),要写比较语句(===)!比如:

let 喜欢奶茶 = false;
if (喜欢奶茶 = true) { // 这里是赋值,不是比较!
  console.log("给你买奶茶"); // 会执行,因为赋值后喜欢奶茶变成true
}

这就像你本来不喜欢奶茶,别人硬塞给你一杯,然后说“你看你喜欢吧”——逻辑完全混乱!最佳实践:条件里只写比较表达式,赋值单独写。

2. switch:高效的“多选一菜单”

当有多个固定选项需要匹配时,switch比if…else更简洁,就像餐厅里的“套餐菜单”,选一个套餐就对应一套服务。语法:

switch (套餐类型) {
  case "汉堡套餐":
    给汉堡;
    break; // 关键!选完就退出
  case "披萨套餐":
    给披萨;
    break;
  default:
    给默认小吃; // 没有匹配项时的兜底
}
核心坑:switch的“穿透效应”

如果忘记写break,JS会继续执行下一个case的代码,就像你点了汉堡套餐,服务员不仅给了汉堡,还自动加了披萨和小吃——完全超出预期!比如:

const 水果 = "香蕉";
switch (水果) {
  case "香蕉":
    console.log("香蕉是$0.48一磅");
    // 没写break!
  case "樱桃":
    console.log("樱桃是$3.00一磅");
    break;
}
// 输出:香蕉是$0.48一磅 → 樱桃是$3.00一磅(穿透了!)

避坑指南:除了故意利用穿透的场景(极少),每个case后面必须加break!另外,switch的匹配是严格相等(===),不会自动类型转换,比如case "1"case 1是两个不同的匹配项。

三、异常处理:JS的“安全网”——与bug和平共处

写代码难免遇到bug(就像走路难免摔跤),异常处理就是给代码装“安全网”,让它摔得轻一点,甚至能爬起来继续走。JS的异常处理核心是try...catch...finally,再加上throw自定义错误。

1. 三兄弟分工:try→尝试,catch→补救,finally→兜底

这三个语句的关系就像“快递签收流程”:

  • try:尝试做一件事(比如签收快递)
  • catch:如果出问题(快递损坏、丢件),就补救
  • finally:不管成没成功(签没签收),必须做的事(比如关门、谢谢快递员)

举个完整例子:

function 签收快递(快递状态) {
  if (快递状态 === "损坏") {
    throw new Error("快递损坏,无法签收"); // 主动抛出错误(丢件了!)
  }
  return "签收成功";
}

try {
  // 尝试签收
  const 结果 = 签收快递("损坏");
  console.log(结果);
} catch (错误) {
  // 出问题了,补救
  console.error("出错了:", 错误.message); // 输出错误信息
  联系商家理赔(); // 补救措施
} finally {
  // 不管怎样都要做
  console.log("快递处理完毕,关门"); // 必执行!
}

输出结果:

出错了:快递损坏,无法签收
快递处理完毕,关门

2. throw:主动“喊救命”——自定义错误

throw就像你发现快递有问题时,主动喊“快递员,这里有问题!”。它可以抛出任意类型的值(字符串、数字、对象),但最佳实践是抛出Error对象,因为它自带name(错误类型)和message(错误信息),方便调试:

// 不推荐:抛出字符串
throw "快递损坏";

// 推荐:抛出Error对象
throw new Error("快递损坏,无法签收"); // name: "Error", message: "快递损坏..."

还可以用更具体的错误类型,比如TypeError(类型错误)、RangeError(范围错误),让错误信息更精准:

function 计算年龄(出生年份) {
  if (typeof 出生年份 !== "number") {
    throw new TypeError("出生年份必须是数字"); // 类型错误
  }
  if (出生年份 < 1900 || 出生年份 > 2024) {
    throw new RangeError("出生年份范围必须是1900-2024"); // 范围错误
  }
  return 2024 - 出生年份;
}

3. finally的“霸道逻辑”:覆盖一切返回值

finally有个很“霸道”的特性:不管try或catch里有没有return,finally都会执行,而且如果finally里有return,会直接覆盖前面的返回值!比如:

function 测试() {
  try {
    return "try的返回值";
  } catch (e) {
    return "catch的返回值";
  } finally {
    return "finally的返回值"; // 覆盖前面的返回值
  }
}

console.log(测试()); // 输出:finally的返回值

这就像你本来想签收快递(return try的结果),但最后不管怎样,都必须执行“关门”(finally的return),直接忽略了之前的想法。避坑指南:finally里尽量不要写return,它的核心用途是“释放资源”(比如关闭文件、断开网络连接),而不是返回值。

4. 错误处理的“避坑红线”

  • 别“吞掉”错误:catch块里不要只写console.log(e),要用console.error(e)(会格式化错误,方便调试),更不要空catch(catch(){}, 相当于把bug藏起来,永远找不到)。
  • 精准捕获:不要用try包裹所有代码,只包裹“可能出错的部分”(比如网络请求、数据解析),否则会掩盖真正的问题。
  • 释放资源:文件、网络连接、定时器等资源,一定要放在finally里释放,避免内存泄漏。

四、总结:控制流与错误处理的“核心心法”

  1. 块语句:用{}划清作用域,let/const是块级作用域,var是“串门户”,坚决不用var。
  2. 条件语句:
    • if…else:警惕假值陷阱,条件里不写赋值,复杂判断用块语句。
    • switch:每个case必加break,用default兜底,匹配是严格相等。
  3. 异常处理:
    • try:包裹可能出错的代码,不滥用。
    • catch:精准处理错误,不吞错,用Error对象。
    • finally:释放资源,不写return。

JS的控制流让代码“有逻辑、会决策”,错误处理让代码“抗造、不脆断”。这两个技能结合起来,你写的代码就从“勉强能跑”变成“稳健可靠”了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿蒙Armon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值