diff --git "a/\345\274\240\351\271\217\347\277\224/20251121.md" "b/\345\274\240\351\271\217\347\277\224/20251121.md" index 3d3e1545aa08c320613f64de8c426a8a547b6838..baa82fb91fee6f1d18d782f5a95b54b15719afae 100644 --- "a/\345\274\240\351\271\217\347\277\224/20251121.md" +++ "b/\345\274\240\351\271\217\347\277\224/20251121.md" @@ -205,4 +205,27 @@ const [first, , third] = [1, 2, 3] // first=1, third=3 ### 12.3 剩余元素 ```javascript const [first, ...rest] = [1, 2, 3, 4] // first=1, rest=[2,3,4] +``` + +### 练习 +```js + let begin =new Date(2023,4,1); + let ending = new Date(2023,5,1); + + let abc = ending.getTime() - begin.getTime(); + let aab = abc/(1000*60*60); + document.write(`2023年5月1日到2023年6月1日 中间间隔:${aab}小时`); + + let a = new Date(); + let year = a.getFullYear(); + let month = a.getMonth() + 1; + let date = a.getDate(); + + let ending = new Date(2026,6,7); + + let abc = ending - a; + let getabc = abc/(1000*60*60*24); + document.write(`${eval(Math.ceil(getabc))}`) + + ``` \ No newline at end of file diff --git "a/\345\274\240\351\271\217\347\277\224/20251124.md" "b/\345\274\240\351\271\217\347\277\224/20251124.md" new file mode 100644 index 0000000000000000000000000000000000000000..b68dae2127f9f73fc263befa8c8f95ffe5fd5018 --- /dev/null +++ "b/\345\274\240\351\271\217\347\277\224/20251124.md" @@ -0,0 +1,478 @@ +## String 的笔记 +### 一、核心概念梳理 +|比较方式| 关键字 / 方法| 作用| 适用场景| +|---|-----|----|----| +|引用比较| ==| 比较对象在堆中的地址| 判断两个变量是否指向同一对象| +|值比较| equals()| 比较字符串的实际内容| 判断字符串内容是否相同| +|忽略大小写值比较| equalsIgnoreCase()| 内容比较,忽略大小写| 如验证码、用户名比较| +|自然顺序比较| compareTo()| 按字典序比较,返回 int| 排序、大小判断| + +### 二、关键原理补充 +- 字符串常量池: +- 直接赋值的字符串(如 String s1 = "abc")会存入常量池,相同值的字符串复用同一对象; +- new String("abc") 会在堆中创建新对象,即使值相同,地址也不同。 +- equals() 底层: +- String 重写了 Object 的 equals(),先判断地址,再逐字符比较内容。 +- compareTo() 规则: +- 返回 0:内容相同; +- 返回负数:当前字符串 < 参数字符串; +- 返回正数:当前字符串 > 参数字符串; +- (按字符的 Unicode 编码逐位比较,第一个不同字符的差值即为返回值) +### 三、完整代码示例 +```java +运行 +public class StringCompareDemo { + public static void main(String[] args) { + // 1. 基础场景:常量池 vs 堆对象 + String s1 = "Java"; // 常量池 + String s2 = "Java"; // 复用常量池对象 + String s3 = new String("Java"); // 堆新对象 + String s4 = new String("Java"); // 堆另一个新对象 + + // 引用比较 (==) + System.out.println("1. 引用比较 (==):"); + System.out.println("s1 == s2: " + (s1 == s2)); // true(同一常量池对象) + System.out.println("s1 == s3: " + (s1 == s3)); // false(地址不同) + System.out.println("s3 == s4: " + (s3 == s4)); // false(两个堆对象) + + // 2. 值比较 (equals()) + System.out.println("\n2. 值比较 (equals()):"); + System.out.println("s1.equals(s2): " + s1.equals(s2)); // true + System.out.println("s1.equals(s3): " + s1.equals(s3)); // true + System.out.println("s3.equals(s4): " + s3.equals(s4)); // true + + // 3. 忽略大小写比较 (equalsIgnoreCase()) + String s5 = "java"; + System.out.println("\n3. 忽略大小写比较:"); + System.out.println("s1.equals(s5): " + s1.equals(s5)); // false + System.out.println("s1.equalsIgnoreCase(s5): " + s1.equalsIgnoreCase(s5)); // true + + // 4. 字典序比较 (compareTo()) + String s6 = "C++"; + String s7 = "Python"; + String s8 = "Java"; + System.out.println("\n4. 字典序比较 (compareTo()):"); + System.out.println("s1.compareTo(s6): " + s1.compareTo(s6)); // 74-67=7(J的Unicode比C大7) + System.out.println("s1.compareTo(s7): " + s1.compareTo(s7)); // 74-80=-6(J比P小6) + System.out.println("s1.compareTo(s8): " + s1.compareTo(s8)); // 0(内容相同) + + // 5. 特殊场景:空字符串/Null + String s9 = ""; + String s10 = null; + System.out.println("\n5. 特殊场景:"); + // 空字符串equals空字符串:true + System.out.println("s9.equals(\"\"): " + s9.equals("")); + // 避免NullPointerException:先判断非空 + System.out.println("s10 == null ? " + (s10 == null)); + // System.out.println(s10.equals(s9)); // 会抛出NullPointerException + } +} +``` +### 四、输出结果 +plaintext +1. 引用比较 (==): +s1 == s2: true +s1 == s3: false +s3 == s4: false + +2. 值比较 (equals()): +s1.equals(s2): true +s1.equals(s3): true +s3.equals(s4): true + +3. 忽略大小写比较: +s1.equals(s5): false +s1.equalsIgnoreCase(s5): true + +4. 字典序比较 (compareTo()): +s1.compareTo(s6): 7 +s1.compareTo(s7): -6 +s1.compareTo(s8): 0 + +5. 特殊场景: +- s9.equals(""): true +- s10 == null ? true +- 五、避坑指南 +- 避免用 == 比较字符串内容:除非明确要判断是否为同一对象; +- Null 安全:调用 equals() 前,确保调用方非 null(或用 Objects.equals(a, b)); +```java +运行 +// 安全写法:避免NullPointerException +System.out.println(Objects.equals(s10, s9)); // false +常量池优化:String.intern() 可将堆字符串加入常量池,复用对象: +java +运行 +String s3 = new String("Java").intern(); +System.out.println(s1 == s3); // true +``` +### 总结 +- 比较内容:优先用 equals()(忽略大小写用 equalsIgnoreCase()); +- 比较地址:用 ==(仅特殊场景需要); +- 排序 / 大小:用 compareTo(); +- 空值处理:注意 Null 安全,推荐 Objects.equals()。 + +## 练习 + +```js + + + + 手机品牌销量排名 (Top 5) + + + + +
+ + + +``` + +### 练习2 ,3,4,5 +```js + let aug = Array("星期日","星期一","星期二","星期三","星期四","星期五","星期天") + let abc = new Date(); + let aaa = abc.getDay(); + let bbb = aug[aaa]; + document.write(`今天的日期是${bbb}`); + + let arr = new Array(5,7,6,3,9,2); + arr.sort(); + console.log(arr); + console.log(arr[5]); + + let aug = new Array(1,2,3,4,5,6); + let aaa = aug.slice(1,5); + console.log(aaa); + + let arr = new Array("长春", "昌图西", "铁岭西", "沈阳北", "绥中北", "北京"); + document.write("途径站:" + arr); + let aaa = arr.reverse(); + document.write("
反向站:"+aaa); +``` + +### 练习6,7,8,9,10,11,12 +```js + +``` +### 练习13 +```js + + + +
+ + + + +
+ 对应字母: +
+
+ + +``` +### 练习14 +```js + + + +
+

用户注册

+
+ + +
+
+ + +
+
+ +
+
+ + +``` \ No newline at end of file diff --git "a/\345\274\240\351\271\217\347\277\224/20251126.md" "b/\345\274\240\351\271\217\347\277\224/20251126.md" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/\345\274\240\351\271\217\347\277\224/20251127.md" "b/\345\274\240\351\271\217\347\277\224/20251127.md" new file mode 100644 index 0000000000000000000000000000000000000000..739528080446c0e51166d4c14e6db3347d61f0ef --- /dev/null +++ "b/\345\274\240\351\271\217\347\277\224/20251127.md" @@ -0,0 +1,495 @@ +# JavaScript 异常处理和程序调试总结 + +## 异常处理基础 + +### try-catch 语句 + +```javascript +try { + // 可能出错的代码 + const result = someUndefinedVariable + 1; +} catch (error) { + // 错误处理 + console.log("发生错误:", error.message); +} +``` + +### try-catch-finally 语句 + +```javascript +try { + console.log("尝试执行代码"); + throw new Error("自定义错误"); +} catch (error) { + console.log("捕获错误:", error.message); +} finally { + console.log("无论是否出错都会执行"); +} +``` + +## 错误类型 + +### Error - 基本错误类型 + +```javascript +try { + throw new Error("这是一个错误"); +} catch (error) { + console.log(error.name); // 'Error' + console.log(error.message); // '这是一个错误' +} +``` + +### TypeError - 类型错误 + +```javascript +try { + const obj = null; + obj.someMethod(); // 尝试调用null的方法 +} catch (error) { + console.log(error.name); // 'TypeError' +} +``` + +### ReferenceError - 引用错误 + +```javascript +try { + console.log(undefinedVariable); // 未定义变量 +} catch (error) { + console.log(error.name); // 'ReferenceError' +} +``` + +### SyntaxError - 语法错误 + +```javascript +try { + eval("const 123abc = 1;"); // 无效的变量名 +} catch (error) { + console.log(error.name); // 'SyntaxError' +} +``` + +### RangeError - 范围错误 + +```javascript +try { + const arr = new Array(-1); // 无效的数组长度 +} catch (error) { + console.log(error.name); // 'RangeError' +} +``` + +### URIError - URI 错误 + +```javascript +try { + decodeURIComponent("%"); // 无效的URI编码 +} catch (error) { + console.log(error.name); // 'URIError' +} +``` + +## 自定义错误 + +### 创建自定义错误类 + +```javascript +class ValidationError extends Error { + constructor(message, field) { + super(message); + this.name = "ValidationError"; + this.field = field; + } +} + +try { + throw new ValidationError("邮箱格式不正确", "email"); +} catch (error) { + console.log(`${error.name}: ${error.message} (字段: ${error.field})`); +} +``` + +### 使用自定义错误 + +```javascript +function validateEmail(email) { + if (!email.includes("@")) { + throw new ValidationError("无效的邮箱地址", "email"); + } + return true; +} + +try { + validateEmail("invalid-email"); +} catch (error) { + if (error instanceof ValidationError) { + console.log(`验证错误: ${error.message}`); + } +} +``` + +## 错误处理模式 + +### 条件判断预防错误 + +```javascript +// 不好的做法 +function getLength(str) { + return str.length; // 如果str为null会出错 +} + +// 好的做法 +function getLengthSafe(str) { + if (str && typeof str === "string") { + return str.length; + } + return 0; +} +``` + +### 可选链操作符 + +```javascript +const user = { + profile: { + name: "John", + }, +}; + +// 传统方式 +const userName = user && user.profile && user.profile.name; + +// 可选链方式 +const userNameSafe = user?.profile?.name; +console.log(userNameSafe); // 'John' + +// 即使属性不存在也不会报错 +const userAge = user?.profile?.age; +console.log(userAge); // undefined +``` + +### 空值合并运算符 + +```javascript +const input = null; +const value = input ?? "默认值"; +console.log(value); // '默认值' + +const count = 0; +const result = count ?? 100; +console.log(result); // 0 (0不是null或undefined) +``` + +## 调试方法 + +### console 调试方法 + +```javascript +// 基本日志 +console.log("普通日志信息"); + +// 警告信息 +console.warn("警告信息"); + +// 错误信息 +console.error("错误信息"); + +// 信息分组 +console.group("用户信息"); +console.log("姓名: John"); +console.log("年龄: 30"); +console.groupEnd(); + +// 表格显示 +const users = [ + { name: "John", age: 30 }, + { name: "Jane", age: 25 }, +]; +console.table(users); + +// 计时功能 +console.time("操作计时"); +// 执行一些操作 +for (let i = 0; i < 1000000; i++) {} +console.timeEnd("操作计时"); // 操作计时: 2.345ms +``` + +### debugger 语句 + +```javascript +function complexCalculation(a, b) { + debugger; // 执行到这里会暂停 + const result = a * b; + return result; +} + +const answer = complexCalculation(5, 10); +console.log(answer); +``` + +### 堆栈跟踪 + +```javascript +function functionA() { + functionB(); +} + +function functionB() { + functionC(); +} + +function functionC() { + console.trace("调用堆栈跟踪"); // 显示调用堆栈 +} + +functionA(); +``` + +## 异步错误处理 + +### Promise 错误处理 + +```javascript +fetch("/api/data") + .then((response) => response.json()) + .then((data) => console.log(data)) + .catch((error) => console.error("请求失败:", error)); +``` + +### async/await 错误处理 + +```javascript +async function fetchData() { + try { + const response = await fetch("/api/data"); + const data = await response.json(); + return data; + } catch (error) { + console.error("获取数据失败:", error); + throw error; // 重新抛出错误 + } +} + +// 调用async函数 +fetchData().catch((error) => { + console.log("外部错误处理:", error); +}); +``` + +### Promise.all 错误处理 + +```javascript +const promises = [ + fetch("/api/users"), + fetch("/api/posts"), + fetch("/api/comments"), +]; + +Promise.all(promises.map((p) => p.catch((e) => e))).then((results) => { + results.forEach((result, index) => { + if (result instanceof Error) { + console.log(`请求 ${index} 失败:`, result.message); + } else { + console.log(`请求 ${index} 成功`); + } + }); +}); +``` + +## 全局错误处理 + +### window.onerror + +```javascript +window.onerror = function (message, source, lineno, colno, error) { + console.log("全局错误:", message); + console.log("错误文件:", source); + console.log("错误位置:", lineno, ":", colno); + return true; // 阻止浏览器默认错误处理 +}; +``` + +### unhandledrejection 事件 + +```javascript +window.addEventListener("unhandledrejection", function (event) { + console.log("未处理的Promise拒绝:", event.reason); + event.preventDefault(); // 阻止浏览器默认错误提示 +}); +``` + +## 性能调试 + +### 性能测量 + +```javascript +// 使用 performance API +performance.mark("start"); + +// 执行需要测量的代码 +for (let i = 0; i < 1000000; i++) {} + +performance.mark("end"); +performance.measure("循环执行时间", "start", "end"); + +const measure = performance.getEntriesByName("循环执行时间")[0]; +console.log(`执行时间: ${measure.duration}ms`); +``` + +### 内存使用检查 + +```javascript +// 检查内存使用情况 +const memory = performance.memory; +console.log("已使用内存:", memory.usedJSHeapSize); +console.log("内存限制:", memory.jsHeapSizeLimit); +console.log("总堆大小:", memory.totalJSHeapSize); +``` + +## 最佳实践 + +### 具体的错误信息 + +```javascript +// 不好的做法 +throw new Error("操作失败"); + +// 好的做法 +throw new Error("用户注册失败: 邮箱已被使用"); +``` + +### 适当的错误层级 + +```javascript +function processUserData(userData) { + try { + validateUserData(userData); + saveToDatabase(userData); + } catch (error) { + if (error instanceof ValidationError) { + // 处理验证错误 + showUserError(error.message); + } else { + // 处理系统错误 + logSystemError(error); + showGenericError(); + } + } +} +``` + +### 错误日志记录 + +```javascript +function logError(error, context = {}) { + const errorLog = { + timestamp: new Date().toISOString(), + message: error.message, + stack: error.stack, + type: error.name, + context: context, + }; + + // 发送到错误监控服务 + sendToErrorService(errorLog); + + // 开发环境下在控制台显示 + if (process.env.NODE_ENV === "development") { + console.error("错误详情:", errorLog); + } +} +``` + +## 训练 + +```html + +``` + +- 效果图 + +![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第九章训练.gif) + +## 综合 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第九章综合.gif) diff --git "a/\345\274\240\351\271\217\347\277\224/20251128.md" "b/\345\274\240\351\271\217\347\277\224/20251128.md" new file mode 100644 index 0000000000000000000000000000000000000000..ede572ac111d9e506064a13680880a936c415482 --- /dev/null +++ "b/\345\274\240\351\271\217\347\277\224/20251128.md" @@ -0,0 +1,490 @@ +## JavaScript 异常处理与程序调试笔记 +### 一、JavaScript 异常处理核心 +1. 异常的定义与类型 +- 本质:程序执行时偏离预期逻辑的意外事件,未处理会导致程序终止或产生错误输出。 +- 核心价值:增强程序健壮性(容错)、提升错误可排查性、优化用户体验。 +- JS 常见异常类型(基于 Error 类派生): +- 异常类型 +- 触发场景 +示例 +- SyntaxError(语法错误) +- 代码违反 JS 语法规则(编译期报错) +- let a = 10; const a = 20;(重复声明) +- ReferenceError(引用错误) +- 访问未声明的变量 / 函数 / 属性 +- console.log(undefVar); +- TypeError(类型错误) +- 操作不符合变量类型要求 +- const str = '123'; str.push(4); +- RangeError(范围错误) +- 数值超出有效范围 +- [].length = -1;(数组长度为负数) +- URIError(URI 错误) +- encodeURI/decodeURI 处理无效 URI 时 +- decodeURI('%');(不完整的编码字符) +- 自定义异常 +- 业务逻辑错误(如参数非法、接口请求失败) +- 用户 ID 为空、登录态失效 + +2. 异常处理基本原则 +- 不滥用捕获:仅捕获可预测的异常,避免用 catch (e) {} 吞掉所有错误; +- 错误信息明确:包含「场景 + 原因 + 关键参数」,便于排查; +- 可恢复优先:处理后尽量让程序回归正常流程(如默认值兜底、重试); +- 避免阻塞主线程:异步操作的异常需单独处理,不影响整体执行。 + +### 二、异常处理语法 +1. 基础结构:try-catch-finally +语法格式 +```js +try { + // 可能抛出异常的代码(如 DOM 操作、接口请求、类型转换) +} catch (error) { + // 捕获异常后的处理逻辑(如打印日志、提示用户) + console.error("异常触发:", error); +} finally { + // 无论是否异常,必执行的代码(如释放资源、关闭弹窗) +} +``` + +- 核心说明 +- try:包裹 “风险代码”,仅能有一个; +- catch (error):捕获 try 中抛出的异常,error 对象包含 3 个关键属性: +- name:异常类型(如 TypeError); +- message:异常描述信息(如 str.push is not a function); +- stack:异常调用栈(包含文件名、行号,排查核心); +- finally:可选,常用于清理资源(如关闭文件、取消请求),即使 try/catch 中有 return 也会执行。 +示例:处理类型错误 +```js +function formatData(data) { + try { + // 假设 data 应为对象,尝试获取属性 + return data.name || "默认名称"; + } catch (error) { + // 捕获类型错误(如 data 是 null/undefined/字符串) + if (error instanceof TypeError) { + console.error("数据格式错误:", error.message); + return "默认名称"; // 兜底返回 + } + // 非预期异常重新抛出,避免吞掉 + throw error; + } finally { + console.log("数据格式化流程结束"); + } +} + +formatData(123); // 输出:数据格式错误:Cannot read properties of number (reading 'name') → 返回 "默认名称" +``` + +2. 主动抛出异常:throw 语句 +- 语法格式 +- throw 异常对象; // 可抛出 Error 实例、字符串、数字等(推荐 Error 实例) + +- 最佳实践 +- 优先抛出 Error 派生实例(保留 stack 调用栈),而非纯字符串 / 数字; +- 用于业务异常(如参数校验失败),明确中断异常流程。 +- 示例:主动抛出业务异常 +```js +function login(username, password) { + // 参数校验:主动抛出异常 + if (!username) { + throw new Error("业务异常:用户名不能为空"); + } + if (password.length { + throw new TypeError("业务异常:密码长度不能小于 6 位"); + } + // 正常登录逻辑... +} + +try { + login("zhangsan", "123"); +} catch (error) { + console.error(error.message); // 输出:业务异常:密码长度不能小于 6 位 +} +``` + +3. 自定义异常类 +场景 +区分 “系统异常” 和 “业务异常”,便于精准处理(如业务异常提示用户,系统异常上报监控)。 +实现方式(继承 Error 类) +// 自定义业务异常类 +```js +class BusinessError extends Error { + constructor(code, message) { + super(message); // 继承 Error 的 message 属性 + this.name = "BusinessError"; // 自定义异常名称(默认是 Error) + this.code = code; // 自定义错误码(如 400 参数错误、401 未授权) + } +} + +// 使用自定义异常 +function getUserInfo(userId) { + if (!userId) { + throw new BusinessError(400, "用户 ID 不能为空"); + } + if (typeof userId !== "string") { + throw new BusinessError(400, "用户 ID 必须是字符串类型"); + } + // 正常获取用户信息逻辑... +} + +// 捕获并区分异常 +try { + getUserInfo(123); +} catch (error) { + if (error instanceof BusinessError) { + // 业务异常:提示用户 + alert(`错误(${error.code}):${error.message}`); + } else { + // 系统异常:上报监控 + console.error("系统异常:", error); + // reportErrorToMonitor(error); // 伪代码:上报监控 + } +} +``` + +4. 异步操作的异常处理 +```js +(1)回调函数(Callback) +无 try-catch 机制,通过 “错误优先回调”(第一个参数为 error)处理: +const fs = require("fs"); // Node.js 模块 + +// 错误优先回调:err 为 null 表示无异常 +fs.readFile("test.txt", "utf8", (err, data) => { + if (err) { + console.error("文件读取失败:", err.message); + return; + } + console.log("文件内容:", data); +}); + +(2)Promise +方式 1:then 的第二个参数(仅捕获当前 Promise 的异常); +方式 2:catch 方法(捕获整个 Promise 链的异常,推荐); +// 模拟异步接口请求 +function fetchData() { + return new Promise((resolve, reject) => { + setTimeout(() => { + const success = false; + if (success) { + resolve({ code: 200, data: "成功数据" }); + } else { + reject(new Error("接口请求失败:服务器错误")); // 主动 reject 抛出异常 + } + }, 1000); + }); +} + +// 异常处理 +fetchData() + .then( + (res) => console.log("结果:", res), + (err) => console.error("then 捕获异常:", err) // 仅捕获 fetchData 的异常 + ) + .catch((err) => { + console.error("catch 捕获异常:", err); // 捕获整个链的异常(包括 then 中的错误) + }); + +(3)async/await +支持 try-catch-finally 语法,异常处理更直观(推荐): +async function getData() { + try { + const res = await fetchData(); // 等待 Promise 完成 + console.log("结果:", res); + return res; + } catch (error) { + // 捕获 fetchData 抛出的异常,或 await 后的代码异常 + console.error("异步请求异常:", error.message); + return null; // 兜底返回 + } finally { + console.log("异步请求流程结束"); + } +} + +getData(); +``` + +### 三、JavaScript 程序调试技巧 +1. 基础调试:console 系列 +- (1)常用方法 +- 方法 +- 用途 +- 示例 +- console.log() +- 输出普通信息(支持多参数、模板字符串) +- console.log("用户数据:", user, age); +- console.error() +- 输出错误信息(红色标记,保留调用栈) +- console.error("参数错误:", err); +- console.warn() +- 输出警告信息(黄色标记) +- console.warn("数据格式过时"); +- console.table() +- 格式化输出数组 / 对象(表格形式) +- console.table([{name: "张三"}, {name: "李四"}]); +- console.dir() +- 详细打印对象结构(展开所有属性) +- console.dir(document.body); +- console.time()/console.timeEnd() +- 计算代码执行时间 +- console.time("循环耗时"); for(let i=0;i;i++); console.timeEnd("循环耗时"); + +(2)占位符用法 +- console.log("姓名:%s,年龄:%d,是否成年:%s", "张三", 20, true); +- // 输出:姓名:张三,年龄:20,是否成年:true +- // 占位符:%s(字符串)、%d(数字)、%o(对象)、%c(样式) +- console.log("%c重要提示", "color: red; font-size: 16px;"); // 带样式输出 + +2. 浏览器调试工具(Chrome 为例) +-(1)调试面板核心功能(F12 打开) +- 面板 +- 用途 +- 关键操作 +- Sources +- 断点调试、查看源代码 +- 1. 点击行号添加断点;2. F5 刷新触发;3. 单步调试(F10 步过、F11 步入、Shift+F11 步出) +- Console +- 执行临时代码、查看日志 +- 输入变量名查看值,支持 $0(当前选中元素)、$_(上一次结果) +- Network +- 监控网络请求(接口、资源加载) +- 筛选 XHR/Fetch 请求,查看请求头、响应体、耗时 +- Application +- 查看存储(LocalStorage、Cookie)、DOM 结构 + -修改存储数据后实时测试 + -Elements +- 查看 / 修改 DOM 元素和 CSS 样式 +- 断点监听 DOM 变化(右键元素 → Break on) + +(2)断点调试进阶 +- 条件断点:右键断点 → Edit Condition,输入表达式(如 i === 10),仅当表达式为 - - true 时触发; +- 异常断点:Sources 面板 → 勾选 Break on exceptions(暂停图标旁),程序抛出异常时- 自动断点; +- 日志断点:右键断点 → Add log point,输入日志内容(如 循环到第 {i} 次),不中断程- 序仅输出日志。 +3. 调试避坑指南 +- 避免用 alert() 调试:阻塞主线程,无法查看对象结构,且影响异步操作; +- 异步代码调试:async/await 可直接断点,Promise 需在 then/catch 中加断点,或使用日志断点; +- 生产环境调试: +- 保留 source-map(映射压缩前的源代码),但注意安全(避免暴露敏感逻辑); +- 使用 console.debug() 输出调试信息(生产环境可通过浏览器过滤隐藏); +- 排查 NaN/undefined 问题: +- 用 Number.isNaN() 判断 NaN(避免 == NaN,因 NaN 不等于任何值); +- 用 typeof variable === "undefined" 判断未定义变量。 + +### 四、实战场景:异常处理最佳实践 + +1. 接口请求异常处理(fetch 示例) +```js +async function request(url, options = {}) { + try { + const response = await fetch(url, options); + // 处理 HTTP 错误(如 404、500,fetch 仅网络错误会 reject) + if (!response.ok) { + throw new Error(`HTTP 错误:${response.status},${response.statusText}`); + } + const data = await response.json(); + // 处理业务错误(如接口返回 code 非 200) + if (data.code !== 200) { + throw new BusinessError(data.code, data.message); + } + return data.data; + } catch (error) { + if (error instanceof BusinessError) { + alert(`操作失败:${error.message}`); + } else if (error.message.includes("Failed to fetch")) { + alert("网络异常,请检查网络连接"); + } else { + console.error("请求异常:", error); + alert("系统异常,请稍后重试"); + } + return null; + } +} +``` +2. 函数参数校验异常 +```js +function calculateTotal(price, quantity) { + // 参数类型校验 + if (typeof price !== "number" || typeof quantity !== "number") { + throw new TypeError("价格和数量必须是数字类型"); + } + // 参数范围校验 + if (price < 0 || quantity < 0) { + throw new RangeError("价格和数量不能为负数"); + } + return price * quantity; +} + +// 使用时捕获异常 +try { + const total = calculateTotal(100, "5"); // 第二个参数是字符串 + console.log("总价:", total); +} catch (error) { + console.error("计算失败:", error.message); +} +``` +3. 全局异常捕获(兜底处理) +// 捕获同步代码异常 +```js +window.addEventListener("error", (event) => { + console.error("全局同步异常:", event.error); + // 上报监控(伪代码) + // reportError({ + // type: "sync", + // message: event.error.message, + // stack: event.error.stack, + // url: event.filename, + // line: event.lineno, + // column: event.colno + // }); + event.preventDefault(); // 阻止浏览器默认错误提示 +}); + +// 捕获 Promise 未处理的异常(如未加 catch 的 Promise reject) +window.addEventListener("unhandledrejection", (event) => { + console.error("全局 Promise 异常:", event.reason); + // 上报监控 + event.preventDefault(); // 阻止浏览器默认提示 +}); +``` + +五、核心总结 +- 异常处理:优先用 try-catch-finally(同步 /async/await)、Promise.catch(Promise),避免吞掉异常; +- 异常类型:区分系统异常(TypeError 等)和业务异常(自定义 BusinessError),精准处理; +- 调试技巧:浏览器 Sources 面板断点调试 + console 系列工具,高效定位问题; +- 最佳实践:参数校验前置、异常信息明确、全局兜底捕获、生产环境保留调试能力且兼顾安全。 + +## 练习 +```js +

第一题

+
+ +
+ +

第二题

+中国的“国球”是( )
+篮球 +排球 +乒乓球 +羽毛球 + +

第三题

+ + +

欢迎访问本网站当前时间为:

+ + + +

第四题

+ + +

宽度:

+

高度:

+ + + +

第五题

+
+ + + +
+ + +

第六题

+
+ + +

第七题

+
+ 用户名:
+ 密 码:
+
+
+ +``` \ No newline at end of file