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
+
+```
+
+- 效果图
+
+
+
+## 综合
+
+```html
+
+```
+
+- 效果图
+ 
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