[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site-config":3,"footer-socials":22,"article-javascript学习笔记":23,"comments-javascript学习笔记":43},{"site_title":4,"site_subtitle":5,"home_intro":6,"avatar":7,"seo_keywords":8,"seo_description":9,"site_subtitle_highlight":10,"home_description":11,"about_name":12,"about_intro":13,"code_comment_2":14,"code_log":15,"code_skills":16,"code_goal":17,"code_comment_1":18,"meteor_density":19,"meteor_max_count":19,"meteor_enabled":20,"meteor_speed":21},"ShineGoldYao","架构代码，","全栈开发者 \u002F 开源爱好者 \u002F 技术探索者","https:\u002F\u002Fforuda.gitee.com\u002Favatar\u002F1762402862010015318\u002F16382196_yaoxingjin_1762402861.png!avatar200","ShiGoldYao,技术博客,全栈开发","专注于前沿技术分享与开源项目展示的个人技术博客","书写未来。","大家好，我是 ShiGoldYao。一名全栈学习与技术爱好者。在这里，我分享关于现代 Web 开发、技术框架学习记录以及极客生活的深度思考。","ShiGoldYao","我是一名全栈技术学习者，对构建高性能、可扩展的现代 Web 应用充满热情。过去一年里，我从初识互联网前后端开发，到逐步沉淀技术体系，始终保持着对前端、后端与工程化的持续探索。\n\n我坚信 “代码如诗”。除了日常学习与项目实践，我也会花大量时间关注开源社区，尝试摸索 WebAssembly、Rust 等前沿技术在浏览器端的更多可能，不断挑战性能与体验的边界。\n\n生活里的我并不只有代码：闲暇时会打打永劫无间，享受博弈与操作的快感；也喜欢打乒乓球，在运动中放松自己；当然，最幸福的时光，还是和女朋友一起慢慢生活、认真恋爱。","\u002F\u002F 🚀 开启学习之旅","","Vue , TypeScript , Nest , Mysql","成为优秀的前端全栈工程师","\u002F\u002F 欢迎来到我的技术世界","3","true","5",[],{"id":21,"title":24,"slug":25,"coverUrl":15,"summary":15,"content":26,"htmlContent":27,"categoryId":28,"viewCount":29,"likeCount":30,"isTop":30,"isPublish":31,"seoKeywords":15,"seoDescription":15,"publishTime":32,"createTime":33,"updateTime":34,"deleteTime":35,"category":36,"tags":42},"JavaScript 学习笔记","javascript学习笔记","# JavaScript 学习笔记\n\n> 专为前端工程师设计的 JavaScript 基础与 ES6+ 学习笔记\n\n---\n\n## 目录\n\n- [一、JavaScript 简介](#一javascript-简介)\n- [二、基础语法](#二基础语法)\n- [三、数据类型](#三数据类型)\n- [四、运算符](#四运算符)\n- [五、流程控制](#五流程控制)\n- [六、函数](#六函数)\n- [七、对象](#七对象)\n- [八、数组](#八数组)\n- [九、字符串](#九字符串)\n- [十、DOM 操作](#十dom-操作)\n- [十一、事件处理](#十一事件处理)\n- [十二、ES6 新特性](#十二es6-新特性)\n- [十三、异步编程](#十三异步编程)\n- [十四、面向对象](#十四面向对象)\n- [十五、模块化](#十五模块化)\n- [十六、错误处理](#十六错误处理)\n- [十七、实战示例](#十七实战示例)\n- [十八、最佳实践](#十八最佳实践)\n- [十九、快速参考](#十九快速参考)\n\n---\n\n## 一、JavaScript 简介\n\n### 1.1 什么是 JavaScript\n\nJavaScript 是一种轻量级的、解释型的编程语言，主要用于网页开发。\n\n**特点：**\n- 动态类型\n- 弱类型\n- 解释执行\n- 基于原型的面向对象\n- 函数式编程支持\n\n### 1.2 JavaScript 版本\n\n| 版本 | 年份 | 主要特性 |\n|------|------|----------|\n| ES1 | 1997 | 首次发布 |\n| ES3 | 1999 | 正则表达式、try-catch |\n| ES5 | 2009 | 严格模式、JSON |\n| ES6\u002FES2015 | 2015 | let\u002Fconst、箭头函数、类、模块 |\n| ES2016-ES2024 | 2016-2024 | 持续更新新特性 |\n\n### 1.3 JavaScript 引入方式\n\n```html\n\u003C!-- 方式1：内联脚本 -->\n\u003Cscript>\n    console.log('Hello World');\n\u003C\u002Fscript>\n\n\u003C!-- 方式2：外部脚本 -->\n\u003Cscript src=\"script.js\">\u003C\u002Fscript>\n\n\u003C!-- 方式3：模块脚本 -->\n\u003Cscript type=\"module\" src=\"module.js\">\u003C\u002Fscript>\n\n\u003C!-- 方式4：延迟脚本 -->\n\u003Cscript defer src=\"defer.js\">\u003C\u002Fscript>\n\n\u003C!-- 方式5：异步脚本 -->\n\u003Cscript async src=\"async.js\">\u003C\u002Fscript>\n```\n\n---\n\n## 二、基础语法\n\n### 2.1 变量声明\n\n```javascript\n\u002F\u002F var（不推荐，存在变量提升）\nvar name = '张三';\n\n\u002F\u002F let（推荐，块级作用域）\nlet age = 25;\n\n\u002F\u002F const（推荐，常量）\nconst PI = 3.14159;\n\n\u002F\u002F 常量必须初始化\nconst MAX_SIZE = 100;\n\n\u002F\u002F const 声明的对象属性可以修改\nconst person = { name: '张三' };\nperson.name = '李四';\n\n\u002F\u002F 但不能重新赋值\nperson = { name: '王五' };\n```\n\n### 2.2 命名规则\n\n```javascript\n\u002F\u002F 合法命名\nlet userName = '张三';\nlet user_name = '张三';\nlet userName1 = '张三';\nlet $name = '张三';\n\n\u002F\u002F 非法命名\n\u002F\u002F let 1name = '张三';\n\u002F\u002F let user-name = '张三';\n\u002F\u002F let class = '张三';\n\n\u002F\u002F 命名规范\nlet firstName = '张三';\nlet lastName = '李四';\nconst MAX_COUNT = 100;\n```\n\n### 2.3 注释\n\n```javascript\n\u002F\u002F 单行注释\n\n\u002F*\n多行注释\n可以写多行\n*\u002F\n\n\u002F**\n * 文档注释\n * @param {string} name 用户名\n * @returns {string} 问候语\n *\u002F\nfunction greet(name) {\n    return 'Hello, ' + name;\n}\n```\n\n### 2.4 严格模式\n\n```javascript\n\u002F\u002F 启用严格模式\n'use strict';\n\n\u002F\u002F 严格模式下的限制\n\u002F\u002F 不能使用未声明的变量\n\u002F\u002F 不能删除变量、函数\n\u002F\u002F 参数名不能重复\n\u002F\u002F eval 更安全\n```\n\n---\n\n## 三、数据类型\n\n### 3.1 基本数据类型\n\n```javascript\n\u002F\u002F 数字\nlet num = 42;\nlet float = 3.14;\nlet infinity = Infinity;\nlet nan = NaN;\n\n\u002F\u002F 字符串\nlet str = 'Hello';\nlet str2 = \"World\";\nlet str3 = `Hello ${str}`; \u002F\u002F 模板字符串\n\n\u002F\u002F 布尔值\nlet bool = true;\nlet bool2 = false;\n\n\u002F\u002F undefined\nlet undef = undefined;\n\n\u002F\u002F null\nlet empty = null;\n\n\u002F\u002F Symbol（ES6）\nlet sym = Symbol('description');\n\n\u002F\u002F BigInt（ES2020）\nlet bigNum = 9007199254740991n;\n```\n\n### 3.2 引用数据类型\n\n```javascript\n\u002F\u002F 对象\nlet obj = {\n    name: '张三',\n    age: 25\n};\n\n\u002F\u002F 数组\nlet arr = [1, 2, 3, 4, 5];\n\n\u002F\u002F 函数\nlet func = function() {\n    console.log('Hello');\n};\n\n\u002F\u002F 日期\nlet date = new Date();\n\n\u002F\u002F 正则表达式\nlet regex = \u002Fpattern\u002Fg;\n\n\u002F\u002F Map（ES6）\nlet map = new Map();\nmap.set('key', 'value');\n\n\u002F\u002F Set（ES6）\nlet set = new Set();\nset.add(1);\n```\n\n### 3.3 类型检测\n\n```javascript\n\u002F\u002F typeof\ntypeof 42; \u002F\u002F 'number'\ntypeof 'hello'; \u002F\u002F 'string'\ntypeof true; \u002F\u002F 'boolean'\ntypeof undefined; \u002F\u002F 'undefined'\ntypeof null; \u002F\u002F 'object'（历史遗留问题）\ntypeof {}; \u002F\u002F 'object'\ntypeof []; \u002F\u002F 'object'\ntypeof function() {}; \u002F\u002F 'function'\n\n\u002F\u002F instanceof\n[] instanceof Array; \u002F\u002F true\n{} instanceof Object; \u002F\u002F true\nnew Date() instanceof Date; \u002F\u002F true\n\n\u002F\u002F Object.prototype.toString\nObject.prototype.toString.call([]); \u002F\u002F '[object Array]'\nObject.prototype.toString.call({}); \u002F\u002F '[object Object]'\nObject.prototype.toString.call(null); \u002F\u002F '[object Null]'\n\n\u002F\u002F Array.isArray\nArray.isArray([]); \u002F\u002F true\nArray.isArray({}); \u002F\u002F false\n\n\u002F\u002F isNaN\nisNaN(NaN); \u002F\u002F true\nisNaN('hello'); \u002F\u002F true\n\n\u002F\u002F Number.isNaN（ES6）\nNumber.isNaN(NaN); \u002F\u002F true\nNumber.isNaN('hello'); \u002F\u002F false\n```\n\n### 3.4 类型转换\n\n```javascript\n\u002F\u002F 字符串转换\nString(123); \u002F\u002F '123'\nString(true); \u002F\u002F 'true'\nString(null); \u002F\u002F 'null'\nString(undefined); \u002F\u002F 'undefined'\n\n\u002F\u002F 数字转换\nNumber('123'); \u002F\u002F 123\nNumber('hello'); \u002F\u002F NaN\nNumber(true); \u002F\u002F 1\nNumber(false); \u002F\u002F 0\n\n\u002F\u002F 布尔转换\nBoolean(0); \u002F\u002F false\nBoolean(''); \u002F\u002F false\nBoolean(null); \u002F\u002F false\nBoolean(undefined); \u002F\u002F false\nBoolean(NaN); \u002F\u002F false\nBoolean([]); \u002F\u002F true\nBoolean({}); \u002F\u002F true\n\n\u002F\u002F parseInt\nparseInt('123'); \u002F\u002F 123\nparseInt('123.45'); \u002F\u002F 123\nparseInt('hello'); \u002F\u002F NaN\nparseInt('123px'); \u002F\u002F 123\n\n\u002F\u002F parseFloat\nparseFloat('123.45'); \u002F\u002F 123.45\nparseFloat('123.45px'); \u002F\u002F 123.45\n```\n\n---\n\n## 四、运算符\n\n### 4.1 算术运算符\n\n```javascript\nlet a = 10, b = 3;\n\n\u002F\u002F 基本运算\na + b; \u002F\u002F 13\na - b; \u002F\u002F 7\na * b; \u002F\u002F 30\na \u002F b; \u002F\u002F 3.333...\na % b; \u002F\u002F 1（取余）\na ** b; \u002F\u002F 1000（幂运算）\n\n\u002F\u002F 自增自减\na++; \u002F\u002F 10，然后 a 变为 11\n++a; \u002F\u002F 12\na--; \u002F\u002F 12，然后 a 变为 11\n--a; \u002F\u002F 10\n```\n\n### 4.2 比较运算符\n\n```javascript\nlet a = 10, b = '10';\n\n\u002F\u002F 相等比较\na == b; \u002F\u002F true（类型转换）\na === b; \u002F\u002F false（严格比较）\n\n\u002F\u002F 不等比较\na != b; \u002F\u002F false\na !== b; \u002F\u002F true\n\n\u002F\u002F 大小比较\na > 5; \u002F\u002F true\na \u003C 5; \u002F\u002F false\na >= 10; \u002F\u002F true\na \u003C= 10; \u002F\u002F true\n```\n\n### 4.3 逻辑运算符\n\n```javascript\nlet a = true, b = false;\n\n\u002F\u002F 逻辑与\na && b; \u002F\u002F false\na && true; \u002F\u002F true\n\n\u002F\u002F 逻辑或\na || b; \u002F\u002F true\nfalse || b; \u002F\u002F false\n\n\u002F\u002F 逻辑非\n!a; \u002F\u002F false\n!b; \u002F\u002F true\n\n\u002F\u002F 短路运算\nlet name = user && user.name;\nlet value = input || 'default';\n\n\u002F\u002F 空值合并运算符（ES2020）\nlet value = input ?? 'default';\n```\n\n### 4.4 赋值运算符\n\n```javascript\nlet a = 10;\n\n\u002F\u002F 基本赋值\na = 20;\n\n\u002F\u002F 复合赋值\na += 5; \u002F\u002F a = a + 5\na -= 3; \u002F\u002F a = a - 3\na *= 2; \u002F\u002F a = a * 2\na \u002F= 2; \u002F\u002F a = a \u002F 2\na %= 3; \u002F\u002F a = a % 3\na **= 2; \u002F\u002F a = a a ** 2\n```\n\n### 4.5 位运算符\n\n```javascript\nlet a = 5; \u002F\u002F 二进制：101\n\n\u002F\u002F 按位与\na & 3; \u002F\u002F 1（101 & 011 = 001）\n\n\u002F\u002F 按位或\na | 3; \u002F\u002F 7（101 | 011 = 111）\n\n\u002F\u002F 按位异或\na ^ 3; \u002F\u002F 6（101 ^ 011 = 110）\n\n\u002F\u002F 按位非\n~a; \u002F\u002F -6\n\n\u002F\u002F 左移\na \u003C\u003C 1; \u002F\u002F 10（101 \u003C\u003C 1 = 1010）\n\n\u002F\u002F 右移\na >> 1; \u002F\u002F 2（101 >> 1 = 010）\n\n\u002F\u002F 无符号右移\na >>> 1; \u002F\u002F 2\n```\n\n### 4.6 其他运算符\n\n```javascript\n\u002F\u002F 三元运算符\nlet age = 18;\nlet status = age >= 18 ? '成年' : '未成年';\n\n\u002F\u002F 展开运算符（ES6）\nlet arr = [1, 2, 3];\nlet newArr = [...arr, 4, 5]; \u002F\u002F [1, 2, 3, 4, 5]\n\nlet obj = { name: '张三' };\nlet newObj = { ...obj, age: 25 }; \u002F\u002F { name: '张三', age: 25 }\n\n\u002F\u002F 可选链运算符（ES2020）\nlet name = user?.profile?.name;\n\n\u002F\u002F 逗号运算符\nlet a = (1, 2, 3); \u002F\u002F a = 3\n\n\u002F\u002F void 运算符\nvoid 0; \u002F\u002F undefined\n\u003Ca href=\"javascript:void(0)\">链接\u003C\u002Fa>\n```\n\n---\n\n## 五、流程控制\n\n### 5.1 条件语句\n\n```javascript\n\u002F\u002F if 语句\nif (condition) {\n    \u002F\u002F 代码块\n}\n\n\u002F\u002F if-else 语句\nif (condition) {\n    \u002F\u002F 代码块1\n} else {\n    \u002F\u002F 代码块2\n}\n\n\u002F\u002F if-else if-else 语句\nif (condition1) {\n    \u002F\u002F 代码块1\n} else if (condition2) {\n    \u002F\u002F 代码块2\n} else {\n    \u002F\u002F 代码块3\n}\n\n\u002F\u002F switch 语句\nswitch (expression) {\n    case value1:\n        \u002F\u002F 代码块1\n        break;\n    case value2:\n        \u002F\u002F 代码块2\n        break;\n    default:\n        \u002F\u002F 默认代码块\n}\n\n\u002F\u002F 三元运算符\nlet result = condition ? value1 : value2;\n```\n\n### 5.2 循环语句\n\n```javascript\n\u002F\u002F for 循环\nfor (let i = 0; i \u003C 10; i++) {\n    console.log(i);\n}\n\n\u002F\u002F while 循环\nlet i = 0;\nwhile (i \u003C 10) {\n    console.log(i);\n    i++;\n}\n\n\u002F\u002F do-while 循环\nlet i = 0;\ndo {\n    console.log(i);\n    i++;\n} while (i \u003C 10);\n\n\u002F\u002F for-in 循环（遍历对象）\nlet obj = { name: '张三', age: 25 };\nfor (let key in obj) {\n    console.log(key, obj[key]);\n}\n\n\u002F\u002F for-of 循环（遍历数组\u002F字符串）\nlet arr = [1, 2, 3, 4, 5];\nfor (let value of arr) {\n    console.log(value);\n}\n\n\u002F\u002F break 和 continue\nfor (let i = 0; i \u003C 10; i++) {\n    if (i === 5) {\n        break; \u002F\u002F 跳出循环\n    }\n    if (i === 3) {\n        continue; \u002F\u002F 跳过本次循环\n    }\n    console.log(i);\n}\n```\n\n### 5.3 异常处理\n\n```javascript\n\u002F\u002F try-catch 语句\ntry {\n    \u002F\u002F 可能出错的代码\n    throw new Error('出错了');\n} catch (error) {\n    \u002F\u002F 错误处理\n    console.error(error.message);\n} finally {\n    \u002F\u002F 无论是否出错都会执行\n    console.log('finally');\n}\n\n\u002F\u002F throw 语句\nfunction divide(a, b) {\n    if (b === 0) {\n        throw new Error('除数不能为0');\n    }\n    return a \u002F b;\n}\n```\n\n---\n\n## 六、函数\n\n### 6.1 函数声明\n\n```javascript\n\u002F\u002F 函数声明\nfunction greet(name) {\n    return 'Hello, ' + name;\n}\n\n\u002F\u002F 函数表达式\nconst greet = function(name) {\n    return 'Hello, ' + name;\n};\n\n\u002F\u002F 箭头函数（ES6）\nconst greet = (name) => {\n    return 'Hello, ' + name;\n};\n\n\u002F\u002F 简写箭头函数\nconst greet = name => 'Hello, ' + name;\n\n\u002F\u002F 立即执行函数\n(function() {\n    console.log('立即执行');\n})();\n\n\u002F\u002F 箭头函数立即执行\n(() => {\n    console.log('立即执行');\n})();\n```\n\n### 6.2 参数\n\n```javascript\n\u002F\u002F 默认参数（ES6）\nfunction greet(name = 'World') {\n    return 'Hello, ' + name;\n}\n\n\u002F\u002F 剩余参数（ES6）\nfunction sum(...numbers) {\n    return numbers.reduce((a, b) => a + b, 0);\n}\nsum(1, 2, 3, 4, 5); \u002F\u002F 15\n\n\u002F\u002F 参数解构（ES6）\nfunction greet({ name, age }) {\n    return `${name} is ${age} years old`;\n}\ngreet({ name: '张三', age: 25 });\n\n\u002F\u002F 参数验证\nfunction divide(a, b) {\n    if (typeof a !== 'number' || typeof b !== 'number') {\n        throw new TypeError('参数必须是数字');\n    }\n    if (b === 0) {\n        throw new Error('除数不能为0');\n    }\n    return a \u002F b;\n}\n```\n\n### 6.3 作用域\n\n```javascript\n\u002F\u002F 全局作用域\nlet globalVar = 'global';\n\nfunction test() {\n    \u002F\u002F 函数作用域\n    let localVar = 'local';\n    console.log(globalVar); \u002F\u002F 可以访问全局变量\n    console.log(localVar); \u002F\u002F 可以访问局部变量\n}\n\ntest();\n\n\u002F\u002F 块级作用域（ES6）\n{\n    let blockVar = 'block';\n    console.log(blockVar);\n}\n\n\u002F\u002F 闭包\nfunction createCounter() {\n    let count = 0;\n    return function() {\n        return ++count;\n    };\n}\nconst counter = createCounter();\ncounter(); \u002F\u002F 1\ncounter(); \u002F\u002F 2\ncounter(); \u002F\u002F 3\n```\n\n### 6.4 高阶函数\n\n```javascript\n\u002F\u002F 函数作为参数\nfunction map(array, fn) {\n    return array.map(fn);\n}\n\nmap([1, 2, 3], x => x * 2); \u002F\u002F [2, 4, 6]\n\n\u002F\u002F 函数作为返回值\nfunction createMultiplier(multiplier) {\n    return function(number) {\n        return number * multiplier;\n    };\n}\nconst double = createMultiplier(2);\ndouble(5); \u002F\u002F 10\n\n\u002F\u002F 柯里与其他\nfunction curry(fn) {\n    return function curried(...args) {\n        if (args.length >= fn.length) {\n            return fn.apply(this, args);\n        }\n        return function(...moreArgs) {\n            return curried.apply(this, args.concat(moreArgs));\n        };\n    };\n}\n\nconst curriedAdd = curry((a, b, c) => a + b + c);\ncurriedAdd(1)(2)(3); \u002F\u002F 6\n```\n\n---\n\n## 七、对象\n\n### 7.1 对象创建\n\n```javascript\n\u002F\u002F 对象字面量\nlet person = {\n    name: '张三',\n    age: 25,\n    greet: function() {\n        return 'Hello, ' + this.name;\n    }\n};\n\n\u002F\u002F 构造函数\nfunction Person(name, age) {\n    this.name = name;\n    this.age = age;\n}\nlet person = new Person('张三', 25);\n\n\u002F\u002F Object.create\nlet person = Object.create(null);\nperson.name = '张三';\nperson.age = 25;\n\n\u002F\u002F 类（ES6）\n-见第十四章面向对象\n```\n\n### 7.2 对象属性\n\n```javascript\nlet person = {\n    name: '张三',\n    age: 25\n};\n\n\u002F\u002F 访问属性\nperson.name; \u002F\u002F '张三'\nperson['name']; \u002F\u002F '张三'\n\n\u002F\u002F 添加属性\nperson.email = 'zhangsan@example.com';\nperson['phone'] = '13800138000';\n\n\u002F\u002F 删除属性\ndelete person.email;\n\n\u002F\u002F 检查属性\n'name' in person; \u002F\u002F true\nperson.hasOwnProperty('name'); \u002F\u002F true\n\n\u002F\u002F 属性枚举\nfor (let key in person) {\n    console.log(key, person[key]);\n}\n\nObject.keys(person); \u002F\u002F ['name', 'age']\nObject.values(person); \u002F\u002F ['张三', 25]\nObject.entries(person); \u002F\u002F [['name', '张三'], ['age', 25]]\n```\n\n### 7.3 对象方法\n\n```javascript\nlet person = {\n    name: '张三',\n    age: 25,\n    \n    greet: function() {\n        return 'Hello, ' + this.name;\n    },\n    \n    \u002F\u002F 简写方法（ES6）\n    sayHello() {\n        return 'Hello, ' + this.name;\n    }\n};\n\n\u002F\u002F 调用方法\nperson.greet(); \u002F\u002F 'Hello, 张三'\nperson.sayHello(); \u002F\u002F 'Hello, 张三'\n```\n\n### 7.4 对象操作\n\n```javascript\nlet obj1 = { name: '张三' };\nlet obj2 = { age: 25 };\n\n\u002F\u002F 对象合并（ES6）\nlet obj3 = { ...obj1, ...obj2 }; \u002F\u002F { name: '张三', age: 25 }\n\n\u002F\u002F Object.assign\nlet obj3 = Object.assign({}, obj1, obj2);\n\n\u002F\u002F 对象比较\nJSON.stringify(obj1) === JSON.stringify(obj2); \u002F\u002F false\n\n\u002F\u002F 对象克隆\nlet clone = { ...obj1 };\nlet clone = JSON.parse(JSON.stringify(obj1));\n\n\u002F\u002F 对象冻结\nObject.freeze(obj1);\nobj1.name = '李四'; \u002F\u002F 不生效\n\n\u002F\u002F 对象密封\nObject.seal(obj1);\ndelete obj1.name; \u002F\u002F 不生效\n```\n\n---\n\n## 八、数组\n\n### 8.1 数组创建\n\n```javascript\n\u002F\u002F 数组字面量\nlet arr = [1, 2, 3, 4, 5];\n\n\u002F\u002F 构造函数\nlet arr = new Array(1, 2, 3, 4, 5);\n\n\u002F\u002F 指定长度\nlet arr = new Array(5); \u002F\u002F [undefined, undefined, undefined, undefined, undefined]\n\n\u002F\u002F Array.of（ES6）\nlet arr = Array.of(1, 2, 3); \u002F\u002F [1, 2, 3]\n\n\u002F\u002F Array.from（ES6）\nlet arr = Array.from('hello'); \u002F\u002F ['h', 'e', 'l', 'l', 'o']\nlet arr = Array.from({ length: 5 }, (_, i) => i); \u002F\u002F [0, 1, 2, 3, 4]\n```\n\n### 8.2 数组访问\n\n```javascript\nlet arr = [1, 2, 3, 4, 5];\n\n\u002F\u002F 访问元素\narr[0]; \u002F\u002F 1\narr[1]; \u002F\u002F 2\n\n\u002F\u002F 修改元素\narr[0] = 10;\n\n\u002F\u002F 数组长度\narr.length; \u002F\u002F 5\n\n\u002F\u002F 添加元素\narr.push(6); \u002F\u002F [1, 2, 3, 4, 5, 6]\narr.unshift(0); \u002F\u002F [0, 1, 2, 3, 4, 5, 6]\n\n\u002F\u002F删除元素\narr.pop(); \u002F\u002F [0, 1, 2, 3, 4, 5]\narr.shift(); \u002F\u002F [1, 2, 3, 4, 5]\n\n\u002F\u002F 检查元素\narr.includes(3); \u002F\u002F true\narr.indexOf(3); \u002F\u002F 2\n```\n\n### 8.3 数组遍历\n\n```javascript\nlet arr = [1, 2, 3, 4, 5];\n\n\u002F\u002F for 循环\nfor (let i = 0; i \u003C arr.length; i++) {\n    console.log(arr[i]);\n}\n\n\u002F\u002F for-of 循环\nfor (let value of arr) {\n    console.log(value);\n}\n\n\u002F\u002F forEach\narr.forEach((value, index, array) => {\n    console.log(value, index);\n});\n\n\u002F\u002F for-in 循环（不推荐）\nfor (let index in arr) {\n    console.log(arr[index]);\n}\n```\n\n### 8.4 数组方法\n\n```javascript\nlet arr = [1, 2, 3, 4, 5];\n\n\u002F\u002F map\nlet doubled = arr.map(x => x * 2); \u002F\u002F [2, 4, 6, 8, 10]\n\n\u002F\u002F filter\nlet even = arr.filter(x => x % 2 === 0); \u002F\u002F [2, 4]\n\n\u002F\u002F reduce\nlet sum = arr.reduce((a, b) => a + b, 0); \u002F\u002F 15\n\n\u002F\u002F find\nlet found = arr.find(x => x > 3); \u002F\u002F 4\n\n\u002F\u002F findIndex\nlet index = arr.findIndex(x => x > 3); \u002F\u002F 3\n\n\u002F\u002F some\nlet hasEven = arr.some(x => x % 2 === 0); \u002F\u002F true\n\n\u002F\u002F every\nlet allPositive = arr.every(x => x > 0); \u002F\u002F true\n\n\u002F\u002F sort\nlet sorted = arr.sort((a, b) => a - b); \u002F\u002F [1, 2, 3, 4, 5]\n\n\u002F\u002F reverse\nlet reversed = arr.reverse(); \u002F\u002F [5, 4, 3, 2, 1]\n\n\u002F\u002F slice\nlet sliced = arr.slice(1, 3); \u002F\u002F [2, 3]\n\n\u002F\u002F splice\narr.splice(1, 2, 10, 20); \u002F\u002F [1, 10, 20, 4, 5]\n\n\u002F\u002F join\nlet str = arr.join(', '); \u002F\u002F '1, 2, 3, 4, 5'\n\n\u002F\u002F concat\nlet combined = arr.concat([6, 7, 8]); \u002F\u002F [1, 2, 3, 4, 5, 6, 7, 8]\n\n\u002F\u002F flat（ES2019）\nlet nested = [1, [2, [3, [4]]]];\nlet flattened = nested.flat(Infinity); \u002F\u002F [1, 2, 3, 4]\n\n\u002F\u002F flatMap（ES2019）\nlet mapped = arr.flatMap(x => [x, x * 2]); \u002F\u002F [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]\n```\n\n---\n\n## 九、字符串\n\n### 9.1 字符串创建\n\n```javascript\n\u002F\u002F 字符串字面量\nlet str = 'Hello';\nlet str2 = \"World\";\nlet str3 = `Hello ${str}`; \u002F\u002F 模板字符串\n\n\u002F\u002F String 构造函数\nlet str = new String('Hello');\n\n\u002F\u002F 多行字符串\nlet str = `Hello\nWorld`;\n\n\u002F\u002F 转义字符\nlet str = 'Hello\\nWorld'; \u002F\u002F 换行\nlet str = 'Hello\\tWorld'; \u002F\u002F 制表符\nlet str = 'Hello\\'World'; \u002F\u002F 单引号\nlet str = 'Hello\\\"World'; \u002F\u002F 双引号\nlet str = 'Hello\\\\World'; \u002F\u002F 反斜杠\n```\n\n### 9.2 字符串访问\n\n```javascript\nlet str = 'Hello';\n\n\u002F\u002F 访问字符\nstr[0]; \u002F\u002F 'H'\nstr.charAt(0); \u002F\u002F 'H'\n\n\u002F\u002F 字符串长度\nstr.length; \u002F\u002F 5\n\n\u002F\u002F 转换为数组\nlet arr = str.split(''); \u002F\u002F ['H', 'e', 'l', 'l', 'o']\n```\n\n### 9.3 字符串方法\n\n```javascript\nlet str = 'Hello World';\n\n\u002F\u002F 大小写转换\nstr.toUpperCase(); \u002F\u002F 'HELLO WORLD'\nstr.toLowerCase(); \u002F\u002F 'hello world'\n\n\u002F\u002F 去除空格\nstr.trim(); \u002F\u002F 'Hello World'\nstr.trimStart(); \u002F\u002F 'Hello World'\nstr.trimEnd(); \u002F\u002F 'Hello World'\n\n\u002F\u002F 查找\nstr.indexOf('World'); \u002F\u002F 6\nstr.lastIndexOf('o'); \u002F\u002F 7\nstr.includes('World'); \u002F\u002F true\nstr.startsWith('Hello'); \u002F\u002F true\nstr.endsWith('World'); \u002F\u002F true\n\n\u002F\u002F 截取\nstr.slice(0, 5); \u002F\u002F 'Hello'\nstr.substring(0, 5); \u002F\u002F 'Hello'\nstr.substr(0, 5); \u002F\u002F 'Hello'\n\n\u002F\u002F 替换\nstr.replace('World', 'JavaScript'); \u002F\u002F 'Hello JavaScript'\nstr.replace(\u002Fo\u002Fg, 'O'); \u002F\u002F 'HellO WOrld'\n\n\u002F\u002F 分割\nstr.split(' '); \u002F\u002F ['Hello', 'World']\n\n\u002F\u002F 重复（ES6）\nstr.repeat(2); \u002F\u002F 'Hello WorldHello World'\n\n\u002F\u002F 填充（ES2017）\nstr.padStart(20, '*'); \u002F\u002F '********Hello World'\nstr.padEnd(20, '*'); \u002F\u002F 'Hello World********'\n\n\u002F\u002F 模板字符串（ES6）\nlet name = '张三';\nlet age = 25;\nlet message = `姓名：${name}，年龄：${age}`;\n\n\u002F\u002F 多行模板字符串\nlet html = `\n    \u003Cdiv>\n        \u003Ch1>${name}\u003C\u002Fh1>\n        \u003Cp>年龄：${age}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n`;\n```\n\n---\n\n## 十、DOM 操作\n\n### 10.1 获取元素\n\n```javascript\n\u002F\u002F 通过 ID 获取\nlet element = document.getElementById('myId');\n\n\u002F\u002F 通过类名获取\nlet elements = document.getElementsByClassName('myClass');\n\n\u002F\u002F 通过标签名获取\nlet elements = document.getElementsByTagName('div');\n\n\u002F\u002F 通过选择器获取（推荐）\nlet element = document.querySelector('.myClass');\nlet elements = document.querySelectorAll('.myClass');\n\n\u002F\u002F 获取文档元素\ndocument.documentElement; \u002F\u002F \u003Chtml>\ndocument.head; \u002F\u002F \u003Chead>\ndocument.body; \u002F\u002F \u003Cbody>\n```\n\n### 10.2 修改元素\n\n```javascript\nlet element = document.querySelector('.myClass');\n\n\u002F\u002F 修改内容\nelement.textContent = '新文本';\nelement.innerHTML = '\u003Cstrong>新HTML\u003C\u002Fstrong>';\n\n\u002F\u002F 修改属性\nelement.setAttribute('src', 'image.jpg');\nelement.src = 'image.jpg';\n\n\u002F\u002F 修改样式\nelement.style.color = 'red';\nelement.style.fontSize = '16px';\n\n\u002F\u002F 添加类\nelement.classList.add('active');\n\n\u002F\u002F 删除类\nelement.classList.remove('active');\n\n\u002F\u002F 切换类\nelement.classList.toggle('active');\n\n\u002F\u002F 检查类\nelement.classList.contains('active'); \u002F\u002F true\n\n\u002F\u002F 替换类\nelement.classList.replace('old', 'new');\n```\n\n### 10.3 创建和删除元素\n\n```javascript\n\u002F\u002F 创建元素\nlet div = document.createElement('div');\ndiv.textContent = '新元素';\ndiv.className = 'new-element';\n\n\u002F\u002F 添加元素\ndocument.body.appendChild(div);\n\n\u002F\u002F 插入元素\nlet parent = document.querySelector('.parent');\nlet child = document.querySelector('.child');\nparent.insertBefore(div, child);\n\n\u002F\u002F 替换元素\nparent.replaceChild(div, child);\n\n\u002F\u002F 删除元素\nparent.removeChild(child);\nchild.remove();\n\n\u002F\u002F 克隆元素\nlet clone = div.cloneNode(true);\n```\n\n### 10.4 事件监听\n\n```javascript\nlet button = document.querySelector('button');\n\n\u002F\u002F 添加事件监听\nbutton.addEventListener('click', function(event) {\n    console.log('按钮被点击');\n    console.log(event.target);\n});\n\n\u002F\u002F 移除事件监听\nfunction handleClick(event) {\n    console.log('按钮被点击');\n}\nbutton.addEventListener('click', handleClick);\nbutton.removeEventListener('click', handleClick);\n\n\u002F\u002F 事件委托\ndocument.addEventListener('click', function(event) {\n    if (event.target.classList.contains('button')) {\n        console.log('按钮被点击');\n    }\n});\n```\n\n---\n\n## 十一、事件处理\n\n### 11.1 事件类型\n\n```javascript\n\u002F\u002F 鼠标事件\nelement.addEventListener('click', handler);\nelement.addEventListener('dblclick', handler);\nelement.addEventListener('mousedown', handler);\nelement.addEventListener('mouseup', handler);\nelement.addEventListener('mousemove', handler);\nelement.addEventListener('mouseover', handler);\nelement.addEventListener('mouseout', handler);\nelement.addEventListener('mouseenter', handler);\nelement.addEventListener('mouseleave', handler);\n\n\u002F\u002F 键盘事件\nelement.addEventListener('keydown', handler);\nelement.addEventListener('keyup', handler);\nelement.addEventListener('keypress', handler);\n\n\u002F\u002F 表单事件\nelement.addEventListener('submit', handler);\n);\nelement.addEventListener('change', handler);\nelement.addEventListener('input', handler);\nelement.addEventListener('focus', handler);\nelement.addEventListener('blur', handler);\n\n\u002F\u002F 窗口事件\nwindow.addEventListener('load', handler);\nwindow.addEventListener('resize', handler);\nwindow.addEventListener('scroll', handler);\nwindow.addEventListener('beforeunload', handler);\n```\n\n### 11.2 事件对象\n\n```javascript\nelement.addEventListener('click', function(event) {\n    \u002F\u002F 事件目标\n    event.target;\n    \n    \u002F\u002F 事件类型\n    event.type;\n    \n    \u002F\u002F 阻止事件冒泡\n    event.stopPropagation();\n    \n    \u002F\u002F 阻止默认行为\n    event.preventDefault();\n    \n    \u002F\u002F 鼠标位置\n    event.clientX;\n    event.clientY;\n    event.pageX;\n    event.pageY;\n    \n    \u002F\u002F 键盘按键\n    event.key;\n    event.keyCode;\n    \n    \u002F\u002F 表单数据\n    event.target.value;\n});\n```\n\n### 11.3 事件委托\n\n```javascript\n\u002F\u002F 事件委托示例\ndocument.addEventListener('click', function(event) {\n    let button = event.target.closest('button');\n    if (button) {\n        console.log('按钮被点击：', button.textContent);\n    }\n});\n\n\u002F\u002F 动态添加元素\nfunction addButton(text) {\n    let button = document.createElement('button');\n    button.textContent = text;\n    document.body.appendChild(button);\n}\n```\n\n---\n\n## 十二、ES6 新特性\n\n### 12.1 let 和 const\n\n```javascript\n\u002F\u002F let：块级作用域变量\nlet name = '张三';\nif (true) {\n    let name = '李四';\n    console.log(name); \u002F\u002F '李四'\n}\nconsole.log(name); \u002F\u002F '张三'\n\n\u002F\u002F const：常量\nconst PI = 3.14159;\n\u002F\u002F PI = 3.14; \u002F\u002F 错误\n\n\u002F\u002F const 声明的对象可以修改\nconst person = { name: '张三' };\nperson.name = '李四'; \u002F\u002F 正确\n\u002F\u002F person = { name: '王五' }; \u002F\u002F 错误\n```\n\n### 12.2 模板字符串\n\n```javascript\nlet name = '张三';\nlet age = 25;\n\n\u002F\u002F 基本用法\nlet message = `姓名：${name}，年龄：${age}`;\n\n\u002F\u002F 多行字符串\nlet html = `\n    \u003Cdiv>\n        \u003Ch1>${name}\u003C\u002Fh1>\n        \u003Cp>年龄：${age}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n`;\n\n\u002F\u002F 表达式\nlet result = `1 + 2 = ${1 + 2}`;\n\n\u002F\u002F 函数调用\nlet message = `当前时间：${new Date().toLocaleString()}`;\n```\n\n### 12.3 解构赋值\n\n```javascript\n\u002F\u002F 数组解构\nlet [a, b, c] = [1, 2, 3];\nconsole.log(a, b, c); \u002F\u002F 1 2 3\n\n\u002F\u002F 默认值\nlet [a, b, c = 3] = [1, 2];\nconsole.log(a, b, c); \u002F\u002F 1 2 3\n\n\u002F\u002F 剩余元素\nlet [a, ...rest] = [1, 2, 3, 4, 5];\nconsole.log(a, rest); \u002F\u002F 1 [2, 3, 4, 5]\n\n\u002F\u002F 对象解构\nlet { name, age } = { name: '张三', age: 25 };\nconsole.log(name, age); \u002F\u002F '张三' 25\n\n\u002F\u002F 重命名\nlet { name: userName, age: userAge } = { name: '张三', age: 25 };\nconsole.log(userName, userAge); \u002F\u002F '张三' 25\n\n\u002F\u002F 默认值\nlet { name = '默认', age = 0 } = {};\nconsole.log(name, age); \u002F\u002F '默认' 0\n\n\u002F\u002F 函数参数解构\nfunction greet({ name, age }) {\n    return `${name} is ${age} years old`;\n}\ngreet({ name: '张三', age: 25 });\n```\n\n### 12.4 箭头函数\n\n```javascript\n\u002F\u002F 基本语法\nlet add = (a, b) => a + b;\n\n\u002F\u002F 单个参数\nlet square = x => x * x;\n\n\u002F\u002F 无参数\nlet greet = () => 'Hello';\n\n\u002F\u002F 多行代码\nlet sum = (a, b) => {\n    return a + b;\n};\n\n\u002F\u002F 返回对象\nlet createPerson = (name, age) => ({ name, age });\n\n\u002F\u002F 作为回调\nlet numbers = [1, 2, 3, 4, 5];\nlet doubled = numbers.map(x => x * 2);\n\n\u002F\u002F this 指向\nlet person = {\n    name: '张三',\n    greet: function() {\n        setTimeout(() => {\n            console.log('Hello, ' + this.name);\n        }, 1000);\n    }\n};\nperson.greet(); \u002F\u002F 'Hello, 张三'\n```\n\n### 12.5 扩展运算符\n\n```javascript\n\u002F\u002F 数组扩展\nlet arr1 = [1, 2, 3];\nlet arr2 = [4, 5, 6];\nlet combined = [...arr1, ...arr2]; \u002F\u002F [1, 2, 3, 4, 5, 6]\n\n\u002F\u002F 数组复制\nlet copy = [...arr1];\n\n\u002F\u002F 对象扩展\nlet obj1 = { name: '张三' };\nlet obj2 = { age: 25 };\nlet combined = { ...obj1, ...obj2 }; \u002F\u002F { name: '张三', age: 25 }\n\n\u002F\u002F 对象复制\nlet copy = { ...obj1 };\n\n\u002F\u002F 函数参数\nfunction sum(...numbers) {\n    return numbers.reduce((a, b) => a + b, 0);\n}\nsum(1, 2, 3, 4, 5); \u002F\u002F 15\n```\n\n### 12.6 对象字面量增强\n\n```javascript\nlet name = '张三';\nlet age = 25;\n\n\u002F\u002F 属性简写\nlet person = { name, age };\n\n\u002F\u002F 方法简写\nlet person = {\n    name: '张三',\n    greet() {\n        return 'Hello, ' + this.name;\n    }\n};\n\n\u002F\u002F 计算属性名\nlet key = 'name';\nlet person = {\n    [key]: '张三'\n};\n\n\u002F\u002F 对象方法\nlet person = {\n    name: '张三',\n    greet() {\n        return 'Hello, ' + this.name;\n    }\n};\n```\n\n### 12.7 数组方法\n\n```javascript\n\u002F\u002F Array.from\nlet arr = Array.from('hello'); \u002F\u002F ['h', 'e', 'l', 'l', 'o']\n\n\u002F\u002F Array.of\nlet arr = Array.of(1, 2, 3); \u002F\u002F [1, 2, 3]\n\n\u002F\u002F find\nlet arr = [1, 2, 3, 4, 5];\nlet found = arr.find(x => x > 3); \u002F\u002F 4\n\n\u002F\u002F findIndex\nlet index = arr.findIndex(x => x > 3); \u002F\u002F 3\n\n\u002F\u002F includes\nlet hasValue = arr.includes(3); \u002F\u002F true\n\n\u002F\u002F keys, values, entries\nfor (let key of arr.keys()) {\n    console.log(key);\n}\n\nfor (let value of arr.values()) {\n    console.log(value);\n}\n\nfor (let [key, value] of arr.entries()) {\n    console.log(key, value);\n}\n```\n\n### 12.8 字符串方法\n\n```javascript\nlet str = 'Hello World';\n\n\u002F\u002F startsWith\nstr.startsWith('Hello'); \u002F\u002F true\n\n\u002F\u002F endsWith\nstr.endsWith('World'); \u002F\u002F true\n\n\u002F\u002F includes\nstr.includes('World'); \u002F\u002F true\n\n\u002F\u002F repeat\nstr.repeat(2); \u002F\u002F 'Hello WorldHello World'\n\n\u002F\u002F padStart\nstr.padStart(20, '*'); \u002F\u002F '********Hello World'\n\n\u002F\u002F padEnd\nstr.padEnd(20, '*'); \u002F\u002F 'Hello World********'\n```\n\n### 12.9 Promise\n\n```javascript\n\u002F\u002F 创建 Promise\nlet promise = new Promise((resolve, reject) => {\n    setTimeout(() => {\n        resolve('成功');\n    }, 1000);\n});\n\n\u002F\u002F then\npromise.then(value => {\n    console.log(value);\n});\n\n\u002F\u002F catch\npromise.catch(error => {\n    console.error(error);\n});\n\n\u002F\u002F finally\npromise.finally(() => {\n    console.log('完成');\n});\n\n\u002F\u002F Promise.all\nPromise.all([promise1, promise2, promise3])\n    .then(values => {\n        console.log(values);\n    });\n\n\u002F\u002F Promise.race\nPromise.race([promise1, promise2, promise3])\n    .then(value => {\n        console.log(value);\n    });\n\n\u002F\u002F Promise.resolve\nlet promise = Promise.resolve('成功');\n\n\u002F\u002F Promise.reject\nlet promise = Promise.reject('失败');\n```\n\n### 12.10 Class\n\n```javascript\n\u002F\u002F 类定义\nclass Person {\n    constructor(name, age) {\n        this.name = name;\n        this.age = age;\n    }\n    \n    greet() {\n        return 'Hello, ' + this.name;\n    }\n}\n\nlet person = new Person('张三', 25);\nperson.greet(); \u002F\u002F 'Hello, 张三'\n\n\u002F\u002F 继承\nclass Student extends Person {\n    constructor(name, age, grade) {\n        super(name, age);\n        this.grade = grade;\n    }\n    \n    study() {\n        return this.name + ' is studying';\n    }\n}\n\nlet student = new Student('李四', 20, 'A');\nstudent.greet(); \u002F\u002F 'Hello, 李四'\nstudent.study(); \u002F\u002F '李四 is studying'\n\n\u002F\u002F 静态方法\nclass MathUtil {\n    static add(a, b) {\n        return a + b;\n    }\n}\nMathUtil.add(1, 2); \u002F\u002F 3\n\n\u002F\u002F getter 和 setter\nclass Person {\n    constructor(name) {\n        this._name = name;\n    }\n    \n    get name() {\n        return this._name;\n    }\n    \n    set name(value) {\n        this._name = value;\n    }\n}\n```\n\n### 12.11 模块化\n\n```javascript\n\u002F\u002F 导出（export.js）\nexport const name = '张三';\nexport function greet() {\n    return 'Hello';\n}\nexport default function() {\n    return 'Default';\n}\n\n\u002F\u002F 导入（import.js）\nimport { name, greet } from '.\u002Fexport.js';\nimport defaultExport from '.\u002Fexport.js';\nimport * as exports from '.\u002Fexport.js';\n\n\u002F\u002F 动态导入\nimport('.\u002Fmodule.js').then(module => {\n    console.log(module);\n});\n```\n\n---\n\n## 十三、异步编程\n\n### 13.1 回调函数\n\n```javascript\n\u002F\u002F 基本回调\nfunction fetchData(callback) {\n    setTimeout(() => {\n        callback('数据');\n    }, 1000);\n}\n\nfetchData(data => {\n    console.log(data);\n});\n\n\u002F\u002F 回调地狱\nfetchData(data1 => {\n    fetchData(data2 => {\n        fetchData(data3 => {\n            console.log(data1, data2, data3);\n        });\n    });\n});\n```\n\n### 13.2 Promise\n\n```javascript\n\u002F\u002F 创建 Promise\nfunction fetchData() {\n    return new Promise((resolve, reject) => {\n        setTimeout(() => {\n            resolve('数据');\n        }, 1000);\n    });\n}\n\n\u002F\u002F 使用 Promise\nfetchData()\n    .then(data => {\n        console.log(data);\n        return '下一个数据';\n    })\n    .then(data => {\n        console.log(data);\n    })\n    .catch(error => {\n        console.error(error);\n    })\n    .finally(() => {\n        console.log('完成');\n    });\n\n\u002F\u002F Promise 链\nfetchData()\n    .then(data1 => fetchData())\n    .then(data2 => fetchData())\n    .then(data3 => {\n        console.log(data3);\n    });\n\n\u002F\u002F Promise.all\nPromise.all([fetchData(), fetchData(), fetchData()])\n    .then(values => {\n        console.log(values);\n    });\n\n\u002F\u002F Promise.race\nPromise.race([fetchData(), fetchData()])\n    .then(value => {\n        console.log(value);\n    });\n```\n\n### 13.3 async\u002Fawait\n\n```javascript\n\u002F\u002F async 函数\nasync function fetchData() {\n    return '数据';\n}\n\n\u002F\u002F await\nasync function main() {\n    let data = await fetchData();\n    console.log(data);\n}\n\n\u002F\u002F 错误处理\nasync function main() {\n    try {\n        let data = await fetchData();\n        console.log(data);\n    } catch (error) {\n        console.error(error);\n    }\n}\n\n\u002F\u002F 并发请求\nasync function main() {\n    let [data1, data2, data3] = await Promise.all([\n        fetchData(),\n        fetchData(),\n        fetchData()\n    ]);\n    console.log(data1, data2, data3);\n}\n\n\u002F\u002F 顺序请求\nasync function main() {\n    let data1 = await fetchData();\n    let data2 = await fetchData();\n    let data3 = await fetchData();\n    console.log(data1, data2, data3);\n}\n```\n\n---\n\n## 十四、面向对象\n\n### 14.1 构造函数\n\n```javascript\n\u002F\u002F 构造函数\nfunction Person(name, age) {\n    this.name = name;\n    this.age = age;\n}\n\n\u002F\u002F 原型方法\nPerson.prototype.greet = function() {\n    return 'Hello, ' + this.name;\n};\n\n\u002F\u002F 创建实例\nlet person = new Person('张三', 25);\nperson.greet(); \u002F\u002F 'Hello, 张三'\n\n\u002F\u002F 原型链\nconsole.log(person instanceof Person); \u002F\u002F true\nconsole.log(person instanceof Object); \u002F\u002F true\n```\n\n### 14.2 原型\n\n```javascript\n\u002F\u002F 原型对象\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.greet = function() {\n    return 'Hello, ' + this.name;\n};\n\n\u002F\u002F 原型继承\nfunction Student(name, grade) {\n    Person.call(this, name);\n    this.grade = grade;\n}\n\nStudent.prototype = Object.create(Person.prototype);\nStudent.prototype.constructor = Student;\n\nStudent.prototype.study = function() {\n    return this.name + ' is studying';\n};\n\nlet student = new Student('李四', 'A');\nstudent.greet(); \u002F\u002F 'Hello, 李四'\nstudent.study(); \u002F\u002F '李四 is studying'\n```\n\n### 14.3 ES6 类\n\n```javascript\n\u002F\u002F 类定义\nclass Person {\n    constructor(name, age) {\n        this.name = name;\n        this.age = age;\n    }\n    \n    greet() {\n        return 'Hello, ' + this.name;\n    }\n    \n    static create(name, age) {\n        return new Person(name, age);\n    }\n}\n\n\u002F\u002F 继承\nclass Student extends Person {\n    constructor(name, age, grade) {\n        super(name, age);\n        this.grade = grade;\n    }\n    \n    study() {\n        return this.name + ' is studying';\n    }\n    \n    greet() {\n        return super.greet() + ' (Student)';\n    }\n}\n\n\u002F\u002F 使用\nlet student = new Student('张三', 20, 'A');\nstudent.greet(); \u002F\u002F 'Hello, 张三 (Student)'\nstudent.study(); \u002F\u002F '张三 is studying'\n\n\u002F\u002F 静态方法\nlet person = Person.create('李四', 25);\n```\n\n---\n\n## 十五、模块化\n\n### 15.1 ES6 模块\n\n```javascript\n\u002F\u002F 导出变量（module.js）\nexport const name = '张三';\nexport const age = 25;\n\n\u002F\u002F 导出函数\nexport function greet() {\n    return 'Hello';\n}\n\n\u002F\u002F 导出类\nexport class Person {\n    constructor(name) {\n        this.name = name;\n    }\n}\n\n\u002F\u002F 默认导出\nexport default function() {\n    return 'Default';\n}\n\n\u002F\u002F 导入（main.js）\nimport { name, age } from '.\u002Fmodule.js';\nimport { greet } from '.\u002Fmodule.js';\nimport { Person } from '.\u002Fmodule.js';\nimport defaultExport from '.\u002Fmodule.js';\n\n\u002F\u002F 导入所有\nimport * as module from '.\u002Fmodule.js';\n\n\u002F\u002F 重命名导入\nimport { name as userName } from '.\u002Fmodule.js';\n```\n\n### 15.2 动态导入\n\n```javascript\n\u002F\u002F 动态导入\nasync function loadModule() {\n    let module = await import('.\u002Fmodule.js');\n    console.log(module);\n}\n\n\u002F\u002F 条件导入\nif (condition) {\n    let module = await import('.\u002Fmodule.js');\n}\n```\n\n---\n\n## 十六、错误处理\n\n### 16.1 try-catch\n\n```javascript\n\u002F\u002F 基本错误处理\ntry {\n    let result = 1 \u002F 0;\n} catch (error) {\n    console.error(error);\n}\n\n\u002F\u002F finally\ntry {\n    let result = 1 \u002F 0;\n} catch (error) {\n    console.error(error);\n} finally {\n    console.log('执行完成');\n}\n```\n\n### 16.2 Error 对象\n\n```javascript\n\u002F\u002F 创建错误\nlet error = new Error('出错了');\nconsole.error(error.message);\n\n\u002F\u002F 错误类型\nlet error = new TypeError('类型错误');\nlet error = new ReferenceError('引用错误');\nlet error = new SyntaxError('语法错误');\nlet error = new RangeError('范围错误');\n\n\u002F\u002F 抛出错误\nfunction divide(a, b) {\n    if (b === 0) {\n        throw new Error('除数不能为0');\n    }\n    return a \u002F b;\n}\n```\n\n### 16.3 Promise 错误处理\n\n```javascript\n\u002F\u002F Promise 错误处理\nlet promise = new Promise((resolve, reject) => {\n    reject('出错了');\n});\n\npromise.catch(error => {\n    console.error(error);\n});\n\n\u002F\u002F async\u002Fawait 错误处理\nasync function fetchData() {\n    try {\n        let data = await fetchData();\n        return data;\n    } catch (error) {\n        console.error(error);\n        throw error;\n    }\n}\n```\n\n---\n\n## 十七、实战示例\n\n### 17.1 表单验证\n\n```javascript\nfunction validateForm(form) {\n    let errors = {};\n    \n    \u002F\u002F 用户名验证\n    let username = form.username.value;\n    if (!username) {\n        errors.username = '用户名不能为空';\n    } else if (username.length \u003C 3) {\n        errors.username = '用户名至少3个字符';\n    }\n    \n    \u002F\u002F 邮箱验证\n    let email = form.email.value;\n    if (!email) {\n        errors.email = '邮箱不能为空';\n    } else if (!\u002F^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\u002F.test(email)) {\n        errors.email = '邮箱格式不正确';\n    }\n    \n    \u002F\u002F 密码验证\n    let password = form.password.value;\n    if (!password) {\n        errors.password = '密码不能为空';\n    } else if (password.length \u003C 6) {\n        errors.password = '密码至少6个字符';\n    }\n    \n    return errors;\n}\n\n\u002F\u002F 使用\nlet form = document.querySelector('form');\nform.addEventListener('submit', function(event) {\n    event.preventDefault();\n    \n    let errors = validateForm(form);\n    \n    if (Object.keys(errors).length > 0) {\n        console.error('表单验证失败：', errors);\n        return;\n    }\n    \n    console.log('表单验证通过');\n});\n```\n\n### 17.2 轮播图\n\n```javascript\nclass Carousel {\n    constructor(container) {\n        this.container = container;\n        this.slides = container.querySelectorAll('.slide');\n        this.currentSlide = 0;\n        this.interval = null;\n        \n        this.init();\n    }\n    \n    init() {\n        this.showSlide(0);\n        this.startAutoPlay();\n        this.bindEvents();\n    }\n    \n    showSlide(index) {\n        this.slides.forEach((slide, i) => {\n            slide.style.display = i === index ? 'block' : 'none';\n        });\n        this.currentSlide = index;\n    }\n    \n    nextSlide() {\n        let nextIndex = (this.currentSlide + 1) % this.slides.length;\n        this.showSlide(nextIndex);\n    }\n    \n    prevSlide() {\n        let prevIndex = (this.currentSlide - 1 + this.slides.length) % this.slides.length;\n        this.showSlide(prevIndex);\n    }\n    \n    startAutoPlay() {\n        this.interval = setInterval(() => {\n            this.nextSlide();\n        }, 3000);\n    }\n    \n    stopAutoPlay() {\n        {\n            clearInterval(this.interval);\n            this.interval = null;\n        }\n    }\n    \n    bindEvents() {\n        this.container.addEventListener('mouseenter', () => {\n            this.stopAutoPlay();\n        });\n        \n        this.container.addEventListener('mouseleave', () => {\n            this.startAutoPlay();\n        });\n    }\n}\n\n\u002F\u002F 使用\nlet carousel = new Carousel(document.querySelector('.carousel'));\n```\n\n### 17.3 数据表格\n\n```javascript\nclass DataTable {\n    constructor(container, data) {\n        this.container = container;\n        this.data = data;\n        this.filteredData = data;\n        this.sortColumn = null;\n        this.sortDirection = 'asc';\n        \n        this.init();\n    }\n    \n    init() {\n        this.render();\n        this.bindEvents();\n    }\n    \n    render() {\n        let table = document.createElement('table');\n        \n        \u002F\u002F 表头\n        let thead = document.createElement('thead');\n        let headerRow = document.createElement('tr');\n        \n        Object.keys(this.data[0]).forEach(column => {\n            let th = document.createElement('th');\n            th.textContent = column;\n            th.dataset.column = column;\n            headerRow.appendChild(th);\n        });\n        \n        thead.appendChild(headerRow);\n        table.appendChild(thead);\n        \n        \u002F\u002F 表体\n        let tbody = document.createElement('tbody');\n        \n        this.filteredData.forEach(row => {\n            let tr = document.createElement('tr');\n            \n            Object.values(row).forEach(value => {\n                let td = document.createElement('td');\n                td.textContent = value;\n                tr.appendChild(td);\n            });\n            \n            tbody.appendChild(tr);\n        });\n        \n        table.appendChild(tbody);\n        this.container.innerHTML = '';\n        this.container.appendChild(table);\n    }\n    \n    sort(column) {\n        if (this.sortColumn === column) {\n            this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';\n        } else {\n            this.sortColumn = column;\n            this.sortDirection = 'asc';\n        }\n        \n        this.filteredData.sort((a, b) => {\n            let valueA = a[column];\n            let valueB = b[column];\n            \n            if (this.sortDirection === 'asc') {\n                return valueA > valueB ? 1 : -1;\n            } else {\n                return valueA \u003C valueB ? 1 : -1;\n            }\n        });\n        \n        this.render();\n    }\n    \n    filter(keyword) {\n        this.filteredData = this.data.filter(row => {\n            return Object.values(row).some(value => {\n                return String(value).toLowerCase().includes(keyword.toLowerCase());\n            });\n        });\n        \n        this.render();\n    }\n    \n    bindEvents() {\n        this.container.addEventListener('click', (event) => {\n            if (event.target.tagName === 'TH') {\n                let column = event.target.dataset.column;\n                this.sort(column);\n            }\n        });\n    }\n}\n\n\u002F\u002F 使用\nlet data = [\n    { name: '张三', age: 25, city: '北京' },\n    { name: '李四', age: 30, city: '上海' },\n    { name: '王五', age: 28, city: '广州' }\n];\n\nlet table = new DataTable(document.querySelector('.table-container'), data);\n```\n\n---\n\n## 十八、最佳实践\n\n### 18.1 代码规范\n\n```javascript\n\u002F\u002F 使用 const 和 let，避免使用 var\nconst name = '张三';\nlet age = 25;\n\n\u002F\u002F 使用模板字符串\nlet message = `姓名：${name}，年龄：${age}`;\n\n\u002F\u002F 使用箭头函数\nlet add = (a, b) => a + b;\n\n\u002F\u002F 使用解构赋值\nlet { name, age } = person;\nlet [first, second] = array;\n\n\u002F\u002F 使用默认参数\nfunction greet(name = 'World') {\n    return 'Hello, ' + name;\n}\n\n\u002F\u002F 使用扩展运算符\nlet combined = [...arr1, ...arr2];\nlet obj = { ...obj1, ...obj2 };\n\n\u002F\u002F 使用对象方法简写\nlet person = {\n    name: '张三',\n    greet() {\n        return 'Hello, ' + this.name;\n    }\n};\n```\n\n### 18.2 性能优化\n\n```javascript\n\u002F\u002F 避免全局变量\nfunction myFunction() {\n    let localVar = 'local';\n}\n\n\u002F\u002F 使用事件委托\n减少事件监听器数量\ndocument.addEventListener('click', function(event) {\n    if (event.target.classList.contains('button')) {\n        \u002F\u002F 处理点击\n    }\n});\n\n\u002F\u002F 防抖\nfunction debounce(fn, delay) {\n    let timer = null;\n    return function(...args) {\n        if (timer) {\n            clearTimeout(timer);\n        }\n        timer = setTimeout(() => {\n            fn.apply(this, args);\n        }, delay);\n    };\n}\n\n\u002F\u002F 节流\nfunction throttle(fn, delay) {\n    let lastTime = 0;\n    return function(...args) {\n        let now = Date.now();\n        if (now - lastTime >= delay) {\n            fn.apply(this, args);\n            lastTime = now;\n        }\n    };\n}\n\n\u002F\u002F 懒加载\nfunction lazyLoad() {\n    let images = document.querySelectorAll('img[data-src]');\n    images.forEach(img => {\n        let rect = img.getBoundingClientRect();\n        if (rect.top \u003C window.innerHeight) {\n            img.src = img.dataset.src;\n            img.removeAttribute('data-src');\n        }\n    });\n}\n\nwindow.addEventListener('scroll', throttle(lazyLoad, 100));\n```\n\n### 18.3 错误处理\n\n```javascript\n\u002F\u002F 全局错误处理\nwindow.addEventListener('error', function(event) {\n    console.error('全局错误：', event.error);\n});\n\nwindow.addEventListener('unhandledrejection', function(event) {\n    console.error('未处理的 Promise 拒绝：', event.reason);\n});\n\n\u002F\u002F 函数错误处理\nasync function fetchData() {\n    try {\n        let response = await fetch('\u002Fapi\u002Fdata');\n        let data = await response.json();\n        return data;\n    } catch (error) {\n        console.error('获取数据失败：', error);\n        throw error;\n    }\n}\n\n\u002F\u002F 参数校验\nfunction divide(a, b) {\n    if (typeof a !== 'number' || typeof b !== 'number') {\n        throw new TypeError('参数必须是数字');\n    }\n    if (b === 0) {\n        throw new Error('除数不能为0');\n    }\n    return a \u002F b;\n}\n```\n\n---\n\n## 十九、快速参考\n\n### 19.1 数据类型\n\n```javascript\n\u002F\u002F 基本类型\nlet num = 42;\nlet str = 'hello';\nlet bool = true;\nlet undef = undefined;\nlet empty = null;\n\n\u002F\u002F 引用类型\nlet obj = { name: '张三' };\nlet arr = [1, 2, 3];\nlet func = function() {};\n```\n\n### 19.2 常用方法\n\n```javascript\n\u002F\u002F 数组方法\narr.map(fn);\narr.filter(fn);\narr.reduce(fn, initial);\narr.find(fn);\narr.includes(value);\n\n\u002F\u002F 字符串方法\nstr.toUpperCase();\nstr.toLowerCase();\nstr.trim();\nstr.split(separator);\nstr.includes(substring);\n\n\u002F\u002F 对象方法\nObject.keys(obj);\nObject.values(obj);\nObject.entries(obj);\n```\n\n### 19.3 ES6 新特性\n\n```javascript\n\u002F\u002F let 和 const\nlet name = '张三';\nconst PI = 3.14159;\n\n\u002F\u002F 箭头函数\nlet add = (a, b) => a + b;\n\n\u002F\u002F 模板字符串\nlet message = `Hello, ${name}`;\n\n\u002F\u002F 解构赋值\nlet { name, age } = person;\nlet [a, b] = [1, 2];\n\n\u002F\u002F 扩展运算符\nlet arr = [...arr1, ...arr2];\nlet obj = { ...obj1, ...obj2 };\n\n\u002F\u002F Promise\nlet promise = new Promise((resolve, reject) => {\n    resolve('成功');\n});\n\n\u002F\u002F async\u002Fawait\nasync function fetchData() {\n    let data = await fetch('\u002Fapi\u002Fdata');\n    return data;\n}\n\n\u002F\u002F 类\nclass Person {\n    constructor(name) {\n        this.name = name;\n    }\n}\n```\n\n---\n\n**祝学习愉快！掌握 JavaScript，开发更强大的应用！** 🚀\n",null,"1",9,0,1,"2026-04-07T16:10:08.611Z","2026-04-07T16:10:08.614Z","2026-05-26T21:24:28.479Z","0",{"id":28,"categoryName":37,"slug":38,"description":39,"sort":30,"isEnable":31,"createTime":40,"updateTime":41,"deleteTime":30},"前端开发","frontend-engineering","2222","2026-04-03T02:36:11.945Z","2026-04-07T16:38:46.496Z",[],[]]