# Javascript进阶 ### 1.字符串操作 #### 1.1.基本方法 - **创建字符串** ```javascript // 字面量 const str1 = "Hello World"; // 构造函数 const str2 = new String("Hello World"); // 模板字符串(ES6) const name = "Alice"; const greeting = `Hello, ${name}!`; // "Hello, Alice!" ``` - **基本属性与方法** ```javascript const str = "JavaScript"; console.log(str.length); // 字符串长度:10 console.log(str[0]); // 访问字符:'J' console.log(str.charAt(5)); // 'S'(索引从0开始) console.log(str.localeCompare("Java")); // 比较字符串:"JavaScript" > "Java" → 1 ``` - **查找与定位** | 方法 | 描述 | 示例 | | :------------------------: | :-----------------------------------------: | :---------------------------------: | | `indexOf(searchValue)` | 返回子字符串首次出现的索引,未找到返回 `-1` | `"apple".indexOf("p")` → `1` | | `lastIndexOf(searchValue)` | 返回子字符串最后一次出现的索引 | `"apple".lastIndexOf("p")` → `2` | | `includes(searchValue)` | 是否包含子字符串(ES6) | `"apple".includes("app")` → `true` | | `startsWith(searchValue)` | 是否以指定字符串开头(ES6) | `"apple".startsWith("ap")` → `true` | | `endsWith(searchValue)` | 是否以指定字符串结尾(ES6) | `"apple".endsWith("le")` → `true` | - **截取与拼接** | 方法 | 描述 | 示例 | | :---------------------: | :----------------------------------: | :----------------------------------------------: | | `concat(str1, str2)` | 合并多个字符串 | `"Hello".concat(" ", "World")` → `"Hello World"` | | `slice(start, end)` | 截取子字符串(支持负数索引) | `"apple".slice(1, -1)` → `"ppl"` | | `substring(start, end)` | 类似 `slice`,但负数索引会被视为 `0` | `"apple".substring(1, 3)` → `"pp"` | | `substr(start, length)` | 从指定位置开始截取指定长度的字符串 | `"apple".substr(1, 3)` → `"ppl"` | - **替换与分割** | 方法 | 描述 | 示例 | | :------------------------------: | :--------------------------: | :--------------------------------------: | | `replace(searchValue, newValue)` | 替换子字符串(仅第一次匹配) | `"apple".replace("p", "x")` → `"axple"` | | `split(separator)` | 按分隔符拆分为数组 | `"a,b,c".split(",")` → `["a", "b", "c"]` | | `trim()` | 去除首尾空白字符 | `" apple ".trim()` → `"apple"` | | `trimStart()`/`trimEnd()` | 去除首/尾空白字符 | `" apple ".trimStart()` → `"apple "` | - **大小写转换** | 方法 | 描述 | 示例 | | :-------------: | :--------: | :---------------------------------: | | `toLowerCase()` | 转换为小写 | `"Apple".toLowerCase()` → `"apple"` | | `toUpperCase()` | 转换为大写 | `"apple".toUpperCase()` → `"APPLE"` | #### 1.2.高阶操作 - **1. 字符串遍历** ``` const str = "hello"; for (let char of str) { console.log(char); // 分别输出 h e l l o } ``` - **统计字符出现次数** ``` function countChars(str) { const counts = {}; for (const char of str) { counts[char] = (counts[char] || 0) + 1; } return counts; } console.log(countChars("aabbc")); // { a: 2, b: 2, c: 1 } ``` - **解析 URL 参数** ``` function getUrlParams(url) { const params = {}; const parser = new URL(url); parser.searchParams.forEach((value, key) => { params[key] = value; }); return params; } const url = "https://example.com?name=Alice&age=25"; console.log(getUrlParams(url)); // { name: 'Alice', age: '25' } ``` - **模板字符串(ES6)** ```javascript const price = 9.99; const message = `Price: $${price.toFixed(2)}`; // "Price: $9.99" ``` #### 1.3.正则表达式 ##### 1.3.1.创建正则 - 字面量 ```javascript const regex = /hello/; // 基础正则 const regexWithFlags = /\d+/ig; // 添加修饰符(i: 忽略大小写,g: 全局匹配) ``` - 构造函数 ```javascript const regex = new RegExp("hello", "g"); // 动态创建正则 ``` - 修饰符 | 修饰符 | 作用 | | ------ | ------------------------ | | `i` | 忽略大小写 | | `g` | 全局匹配(找到所有匹配) | | `m` | 多行匹配(^和$匹配每行) | | `s` | 允许`.`匹配换行符 | ##### 1.3.2.常用符号 **元字符**: | 元字符 | 作用 | 示例 | | ------- | -------------------------- | ---------------------------------- | | `.` | 匹配任意单个字符(除换行) | `/a.c/` 匹配 "abc", "a2c" | | `^` | 匹配字符串开头 | `/^hello/` 匹配以"hello"开头 | | `$` | 匹配字符串结尾 | `/world$/` 匹配以"world"结尾 | | `*` | 匹配前面字符 0 次或多次 | `/ab*/` 匹配 "a", "ab", "abbb" | | `+` | 匹配前面字符 1 次或多次 | `/ab+/` 匹配 "ab", "abbb" | | `?` | 匹配前面字符 0 次或 1 次 | `/colou?r/` 匹配 "color"或"colour" | | `{n}` | 匹配前面字符恰好 n 次 | `/a{3}/` 匹配 "aaa" | | `{n,}` | 匹配前面字符至少 n 次 | `/a{2,}/` 匹配 "aa", "aaa" | | `{n,m}` | 匹配前一个字符 n 到 m 次 | `/a{2,4}/` → 匹配 "aa"~"aaaa" | | `()` | 分组,捕获匹配内容 | `/(ab)+/` → 匹配 "ab"、"abab" | **字符类**: | 表达式 | 作用 | | -------- | ---------------------------- | | `\d` | 匹配数字(0-9) | | `\D` | 匹配非数字 | | `\w` | 匹配字母、数字、下划线 | | `\W` | 匹配非字母、数字、下划线 | | `\s` | 匹配空白字符(空格、换行等) | | `[abc]` | 匹配 a、b 或 c | | `[^abc]` | 匹配非 a、b、c 的字符 | ##### 1.3.3.常用方法 **`RegExp.prototype.test()`** 检查字符串是否匹配正则表达式。 ```javascript const regex = /Hello/; console.log(regex.test('Hello, World!')); // true console.log(regex.test('HELLO')); // false未匹配 大小写 ``` **`RegExp.prototype.exec()`** 执行搜索匹配,返回匹配结果或 `null`。 ```javascript const regex = /Hello/; const result = regex.exec('Hello, World!'); console.log(result); // ['Hello', index: 0, input: 'Hello, World!', groups: undefined] ``` **`match()`** 在字符串中执行搜索匹配,返回匹配结果数组或 `null`。 ```javascript const str = 'Hello, World!'; console.log(str.match(/Hello/)); // ['Hello', index: 0, input: 'Hello, World!', groups: undefined] ``` **`matchAll()`** 返回所有匹配项的迭代器。 ```javascript const str = 'Hello, Hello!'; const regex = /Hello/g; console.log(Array.from(str.matchAll(regex))); // [['Hello', index: 0], ['Hello', index: 7]] ``` **`search()`** 返回第一个匹配项的索引。 ```javascript const str = 'Hello, World!'; console.log(str.search(/World/)); // 7 ``` **`replace()`** 替换字符串中的匹配项。 ```javascript const str = 'Hello, World!'; console.log(str.replace(/World/, 'Alice')); // 'Hello, Alice!' ``` **`split()`** 将字符串拆分为数组。 ```javascript const str = 'Hello, World!'; console.log(str.split(/, /)); // ['Hello', 'World!'] ``` ##### 1.3.4.进阶使用 **捕获组与非捕获组** ```javascript // 捕获组(可通过 `exec` 或 `matchAll` 获取分组内容) const regex = /(a)(b)/; const str = "ab"; const result = regex.exec(str); console.log(result[1]); // "a"(第一个捕获组) console.log(result[2]); // "b"(第二个捕获组) // 非捕获组(仅分组不捕获) const regex2 = /(?:a)(b)/; ``` **前瞻(Lookahead)与后顾(Lookbehind)** 也叫**预查断言** ```javascript // 正向前瞻:匹配后面跟着特定字符的内容 const str = "apple123"; console.log(str.match(/\d+(?=\.)/)); // null(无小数点) console.log("apple123.45".match(/\d+(?=\.)/)); // "123" // 反向前瞻:匹配前面是特定字符的内容 console.log("apple123".match(/(?<=apple)\d+/)); // "123" // 正向后顾:匹配前面是特定字符的内容 console.log("apple123".match(/(?<=apple)\d+/)); // "123" ``` **贪婪与非贪婪匹配** ```javascript const str = "HelloWorld"; // 贪婪匹配(默认) console.log(str.match(/.*<\/div>/)); // "HelloWorld" // 非贪婪匹配(添加 ?) console.log(str.match(/.*?<\/div>/g)); // ["Hello", "World"] ``` **数据提取** ```javascript const text = "Price: $19.99, Quantity: 5"; // 提取价格 const priceMatch = text.match(/\$\d+\.\d+/); console.log(priceMatch[0]); // "$19.99" // 提取所有数字 const numbers = text.match(/\d+/g); console.log(numbers); // ["19", "99", "5"] //提取URL const url = 'https://example.com?name=Alice&age=30'; const params = url.split('?')[1].split('&').reduce((acc, param) => { const [key, value] = param.split('='); acc[key] = value; return acc; }, {}); console.log(params); // { name: 'Alice', age: '30' } ``` **文本替换** ```javascript const str = "Hello WORLD"; // 替换所有大写字母为小写 const newStr = str.replace(/[A-Z]/g, (match) => match.toLowerCase()); console.log(newStr); // "hello world" ``` ##### 1.3.5.常用正则表达式 | **场景** | **正则表达式** | **说明** | | :-------------------------------------: | :----------------------------------------------------: | :----------------------------------------------------------: | | **邮箱验证** | `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` | 基础邮箱验证(允许字母、数字、点、下划线、百分号、加号、减号)。 | | | `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$` | 更严格验证(限制域名长度为 2~6 位)。 | | **手机号验证(中国)** | `^1[3-9]\d{9}$` | 验证中国大陆手机号(11 位,第二位为 3-9)。 | | | `^(13[0-9] | 14[5-9] | | **URL 验证** | `^(https?:\/\/)?([\w.-]+)\.([a-z]{2,})(:\d+)?(\/.*)?$` | 支持 HTTP/HTTPS 协议、域名、端口和路径。 | | | `^https?:\/\/(www\.)?[\w-]+\.[a-z]{2,}(\/.*)?$` | 更简洁的 URL 验证(强制包含 `www.`)。 | | **密码强度验证** | `^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$` | 必须包含大小写字母、数字、特殊字符,长度 ≥8。 | | | `^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,}$` | 简化版(至少字母和数字,长度 ≥8)。 | | **提取 HTML 标签内容** | `<(\w+)>(.*?)<\/\1>` | 匹配简单标签内容(如 `Hello`)。 | | | `<([a-z]+)([^<]+)*(?:>(.*)<\/\1>)?` | 更通用的标签匹配(支持属性和嵌套内容)。 | | **提取 URL 参数** | `[?&]([^=#]+)=([^]*)` | 提取查询字符串中的键值对(如 `name=Alice&age=30`)。 | | | `(?<=[?&])([^=&]+)=([^&]*)` | 使用正向后顾匹配参数键值对。 | | **隐藏手机号中间四位** | `(\d{3})\d{4}(\d{4})` | 将手机号中间四位替换为星号(如 `138****8000`)。 | | | `(\d{3})\d{3}\d{4}` | 另一种替换方式(如 `138-***-8000`)。 | | **千分位分隔符** | `(?]+>` | 删除所有 HTML 标签(如 `Hello → Hello`)。 | | | `<\/?[a-z][\w-]*[^>]*>` | 更全面的标签匹配(支持属性和自闭合标签)。 | | **中文标点转英文标点** | `[,。!?;:“”‘’()《》]` | 替换常见中文标点为英文标点(如 `,→ ,`)。 | | | `[^\x00-\x7F]` | 匹配所有非 ASCII 字符(包括中文标点)。 | | **提取所有数字** | `\d+` | 匹配字符串中的连续数字(如 `abc123def456 → ["123", "456"]`)。 | | | `\b\d+\b` | 匹配独立数字(避免匹配日期中的数字如 `2023-10-05` 中的 `2023`)。 | | **验证身份证号(18位)** | `^\d{15}(\d{2}[0-9xX])?$` | 验证 15 位或 18 位身份证号(最后一位可为 X/x)。 | | | `^[1-9]\d{5}(?:19 | 20)\d{2}(?:0[1-9] | ### 2.对象操作 #### **2.1.对象的创建** ##### 2.1.1. **对象字面量(Literal)** 最简洁的创建方式,直接用 `{}` 定义键值对: ```js const obj = { name: 'dengke', age: 18, sayHi: () => console.log('Hello!'), }; ``` ##### 2.1.2. **`Object` 构造函数** 通过 `new Object()` 创建对象: ```js const obj = new Object(); obj.name = '孙悟空'; // 动态添加属性 ``` ##### 2.1.3. **`Object.create()`** 指定原型链创建对象: ```javascript const prototypeObj = { greet: () => 'Hello' }; const obj = Object.create(prototypeObj); // obj 的原型是 prototypeObj console.log(obj.greet()); // "Hello" ``` ##### 2.1.4. **展开运算符(Spread)** 浅拷贝对象或合并对象: ```js const obj1 = { a: 1 }; const obj2 = { b: 2 }; const merged = { ...obj1, ...obj2 }; // { a:1, b:2 } ``` ##### 2.1.5.类实例化 ```javascript class Person { constructor(name, age){ this.name = name; this.age = age; } } const zs = new Person("zangsan",18); // Person {name:"zangsan".age:18} ``` --- #### **2.2.对象属性操作** ##### 2.2.1. **增删改查** - **添加/修改属性**: ```js obj.newProp = 'value'; // 点语法 obj['dynamicKey'] = 100; // 方括号语法(适合动态键名) ``` - **删除属性**: ```js delete obj.newProp; // 返回布尔值,成功删除返回 true ``` - **访问属性**: ```js console.log(obj.name); // 点语法 console.log(obj['age']); // 方括号语法 ``` ##### 2.2.2. **特殊键名的访问** - 数字或特殊符号键名 必须用方括号语法: ```js const obj = { '1-key': 'value', '-abc': 100 }; console.log(obj['1-key']); // "value" ``` --- #### **2.3.对象遍历** ##### 2.3.1. **`for...in` 循环** 遍历对象自身和继承的可枚举属性: ```js for (const key in obj) { if (obj.hasOwnProperty(key)) { // 过滤原型链属性 console.log(key, obj[key]); } } ``` ##### 2.3.2. **`Object.keys()` / `Object.values()` / `Object.entries()`** - `Object.keys()`:返回对象自身可枚举属性的键数组: ```js const keys = Object.keys(obj); // ["name", "age"] ``` - `Object.values()`:返回属性值的数组: ```javascript const values = Object.values(obj); // ["dengke", 18] ``` - `Object.entries()`:返回键值对数组: ```js const entries = Object.entries(obj); // [["name", "dengke"], ["age", 18]] ``` ##### 2.3.3. **`Reflect.ownKeys()`** 返回对象自身所有属性(包括不可枚举和符号键): ```javascript const allKeys = Reflect.ownKeys(obj); // 包含所有属性 ``` --- #### **2.4.对象属性描述符** ##### 2.4.1. **`Object.defineProperty()`** 定义或修改单个属性的描述符: ```js const obj = {}; Object.defineProperty(obj, 'name', { value: 'dengke', // 属性值 writable: false, // 是否可修改(默认 false) enumerable: true, // 是否可枚举(默认 false) configurable: false // 是否可删除或修改描述符(默认 false) }); ``` ##### 2.4.2. **`Object.defineProperties()`** 批量定义多个属性: ```js Object.defineProperties(obj, { age: { value: 18, writable: true }, gender: { value: 'male', configurable: false } }); ``` ##### 2.4.3. **属性类型** - **数据属性**:直接存储值(如 `name`)。 - **访问器属性**:通过`get`和`set`方法控制访问: ```javascript Object.defineProperty(obj, 'fullName', { get() { return `${this.firstName} ${this.lastName}`; }, set(val) { [this.firstName, this.lastName] = val.split(' '); } }); ``` #### **2.5.对象冻结与密封** ##### 2.5.1. **`Object.freeze()`** 冻结对象,使其不可修改、不可扩展、不可配置: ```javascript const obj = { a: 1 }; Object.freeze(obj); obj.a = 2; // 无效,对象被冻结 ``` ##### 2.5.2. **`Object.seal()`** 密封对象,禁止添加新属性,但允许修改现有属性值: ```javascript Object.seal(obj); obj.b = 3; // 无效,无法添加新属性 obj.a = 2; // 允许修改现有属性 ``` ##### 2.5.3. **`Object.preventExtensions()`** 仅阻止添加新属性,其他操作仍允许: ```javascript Object.preventExtensions(obj); obj.b = 4; // 无效 ``` ##### 2.5.4. **检查对象状态** ```javascript Object.isExtensible(obj); // 是否可扩展 Object.getOwnPropertyDescriptor(obj, 'a'); // 获取属性描述符 ``` --- #### **2.6.对象合并与扩展** ##### 2.6.1. **`Object.assign()`** 合并对象,浅拷贝源对象到目标对象: ```javascript const target = { a: 1 }; const source = { b: 2, a: 3 }; const result = Object.assign(target, source); console.log(result); // { a:3, b:2 }(目标对象被修改) ``` ##### 2.6.2. **展开运算符(Spread)** 与 `Object.assign()` 类似,但语法更简洁: ```javascript const merged = { ...target, ...source }; ``` --- #### **2.7.Reflect API(ES6+)** ##### 2.7.1. **常用方法** - **`Reflect.get()` / `Reflect.set()`**: ```javascript Reflect.get(obj, 'name'); // 等价于 obj.name Reflect.set(obj, 'age', 20); // 等价于 obj.age = 20 ``` - **`Reflect.deleteProperty()`**: ```javascript Reflect.deleteProperty(obj, 'name'); // 等价于 delete obj.name ``` - **`Reflect.construct()`**: ```javascript const Person = function(name) { this.name = name; }; const instance = Reflect.construct(Person, ['dengke']); ``` - **`Reflect.has()`**: ```javascript Reflect.has(obj, 'name'); // 等价于 'name' in obj ``` --- #### 2.8.对象拷贝 ##### 2.8.1.浅拷贝 浅拷贝是指只拷贝对象的**第一层属性**,而嵌套对象的引用仍然指向原始对象。如果原始对象中的嵌套对象被修改,浅拷贝后的对象也会受到影响。 - **`Object.assign()`** ```javascript const obj1 = { a: 1, b: { c: 2 } }; const obj2 = Object.assign({}, obj1); console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 3 (浅拷贝的嵌套对象引用被修改) ``` - **展开运算符 (`...`)** ```javascript const obj1 = { a: 1, b: { c: 2 } }; const obj2 = { ...obj1 }; console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 3 (同样受影响) ``` ##### 2.8.2.深拷贝 - **`JSON.parse()` 和 `JSON.stringify()`** ```javascript const obj1 = { a: 1, b: { c: 2 } }; const obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 2 (深拷贝后的对象不受影响) ``` **局限性**: - 无法处理函数、`undefined`、`Date`、`Map`、`Set` 等特殊对象。 - 无法处理循环引用(会导致栈溢出)。 - **递归实现深拷贝** ```javascript function deepClone(obj, hash = new WeakMap()) { if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const result = Array.isArray(obj) ? [] : {}; hash.set(obj, result); for (const key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key], hash); } } return result; } const obj1 = { a: 1, b: { c: 2 }, d: [3, 4] }; const obj2 = deepClone(obj1); obj1.b.c = 3; console.log(obj2.b.c); // 2 (完全独立) ``` **优点**: - 可以处理复杂对象(如 `Date`、`Map`、`Set` 等)。 - 支持循环引用。 - **使用库(如 Lodash 的 `_.cloneDeep()`)** ```javascript const _ = require('lodash'); const obj1 = { a: 1, b: { c: 2 } }; const obj2 = _.cloneDeep(obj1); obj1.b.c = 3; console.log(obj2.b.c); // 2 (完全独立) ``` #### **2.9.常见陷阱与注意事项** - **浅拷贝问题**:`Object.assign()`和展开运算符仅复制对象的引用,修改嵌套对象会同步到源对象: ``` const obj1 = { a: { b: 1 } }; const obj2 = { ...obj1 }; obj2.a.b = 2; // obj1.a.b 同样变为 2 ``` - **`delete` 操作符的限制**: 无法删除不可配置(`configurable: false`)的属性。 - **`for...in` 的陷阱**: 会遍历原型链属性,需结合`hasOwnProperty()`过滤: ``` for (const key in obj) { if (obj.hasOwnProperty(key)) { // 处理自身属性 } } ``` 1. **`Object.is()` 的特殊比较**: - 与 `===` 不同,`Object.is(-0, 0)` 返回 `false`,而 `NaN === NaN` 返回 `true`。 ### 3.数组操作 #### **3.1.数组的创建** ##### 3.1.1. **字面量方式** 直接用 `[]` 定义数组: ```javascript const arr = [1, 'apple', true]; ``` ##### 3.1.2. **`Array` 构造函数** 通过 `new Array()` 创建: ```javascript const arr1 = new Array(3); // 创建长度为3的空数组 [empty × 3] const arr2 = Array.of(1, 2, 3); // 推荐,避免构造函数的陷阱 ``` ##### 3.1.3. **填充数组** ```javascript const arr = Array(3).fill(0); // [0, 0, 0] ``` --- #### **3.2. 添加元素** ##### **`push()`** - **作用**:向数组末尾添加一个或多个元素,并返回数组的新长度。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.push(4); // arr => [1, 2, 3, 4] ``` ##### **`unshift()`** - **作用**:向数组开头添加一个或多个元素,并返回数组的新长度。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.unshift(0); // arr => [0, 1, 2, 3] ``` ##### **`splice()`** - **作用**:向数组指定位置插入元素。 - **语法**:`arr.splice(index, 0, element1, element2, ...)`。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.splice(1, 0, 'a', 'b'); // arr => [1, 'a', 'b', 2, 3] ``` #### **3.3. 删除元素** ##### **`pop()`** - **作用**:删除数组末尾的元素,并返回被删除的元素。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.pop(); // arr => [1, 2], 返回 3 ``` ##### **`shift()`** - **作用**:删除数组开头的元素,并返回被删除的元素。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.shift(); // arr => [2, 3], 返回 1 ``` ##### **`splice()`** - **作用**:删除数组指定位置的元素。 - **语法**:`arr.splice(index, deleteCount)`。 - **示例**: ```javascript const arr = [1, 2, 3, 4, 5]; arr.splice(2, 1); // arr => [1, 2, 4, 5], 返回 [3] ``` #### **3.4. 查找元素** ##### **`indexOf()`** - **作用**:查找元素在数组中的位置,返回第一个匹配的索引,未找到返回 `-1`。 - **示例**: ```javascript const arr = [1, 2, 3, 2]; arr.indexOf(2); // 返回 1 ``` ##### **`lastIndexOf()`** - **作用**:从数组末尾开始查找元素,返回最后一个匹配的索引,未找到返回 `-1`。 - **示例**: ```javascript const arr = [1, 2, 3, 2]; arr.lastIndexOf(2); // 返回 3 ``` ##### **`find()`** - **作用**:查找数组中第一个满足条件的元素,返回该元素。 - **示例**: ```javascript const arr = [1, 2, 3, 4]; arr.find(item => item > 2); // 返回 3 ``` ##### **`findIndex()`** - **作用**:查找数组中第一个满足条件的元素的索引,未找到返回 `-1`。 - **示例**: ```javascript const arr = [1, 2, 3, 4]; arr.findIndex(item => item > 2); // 返回 2 ``` ##### **`findLast()` / `findLastIndex()`** - **作用**:查找最后一个符合条件的元素: - **示例**: ```javascript const arr = [1, 2, 3, 2]; arr.findLastIndex(x => x === 2); // 3 const arr = [1, 2, 3, 2]; arr.findLast(x => x > 2); //3 ``` #### 3.5.修改元素 ##### **直接赋值** - **作用**:直接修改数组中指定索引的元素。 - **示例**: ```javascript const arr = [1, 2, 3]; arr[1] = 'a'; // arr => [1, 'a', 3] ``` ##### **`splice()`** - **作用**:删除并插入新元素,实现替换功能。 - **语法**:`arr.splice(index, deleteCount, element1, element2, ...)`。 - **示例**: ```javascript const arr = [1, 2, 3, 4, 5]; arr.splice(2, 1, 'a'); // arr => [1, 2, 'a', 4, 5] ``` ##### **`copyWithin`** - **作用**:将数组的一部分复制到同一数组中的另一个位置,覆盖现有值。 - **语法**:`array.copyWithin(target, start, end)` - **示例**: ```javascript const array1 = ["a", "b", "c", "d", "e"]; console.log(array1.copyWithin(0, 3, 4)); // ["d", "b", "c", "d", "e"] console.log(array1.copyWithin(1, 3)); // ["d", "d", "e", "d", "e"] ``` #### **3.6. 遍历与转换** ##### **`map()`** - **作用**:对数组中的每个元素执行函数,并返回一个新数组。 - **示例**: ```javascript const arr = [1, 2, 3]; const newArr = arr.map(item => item * 2); // newArr => [2, 4, 6] ``` ##### **`filter()`** - **作用**:过滤数组中的元素,返回满足条件的新数组。 - **示例**: ```javascript const arr = [1, 2, 3, 4]; const newArr = arr.filter(item => item % 2 === 0); // newArr => [2, 4] ``` ##### **`forEach()`** - **作用**:遍历数组中的每个元素,执行指定函数。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.forEach(item => console.log(item)); // 输出 1, 2, 3 ``` ##### **`entries`** - **作用**:返回一个包含数组中每个索引的键值对的迭代器。 - **语法**:`array.entries()` - **示例**: ```javascript const arr = ['a', 'b', 'c']; for (const [index, value] of arr.entries()) { console.log(index, value); } // 0 'a' // 1 'b' // 2 'c' ``` ##### **`reduce()`** - **作用**:对数组中的元素进行累积操作,返回累积结果。 - **语法**:`arr.reduce(callback(accumulator, currentValue), initialValue)`。 - **示例**: ```javascript const arr = [1, 2, 3, 4]; const sum = arr.reduce((acc, curr) => acc + curr, 0); // sum => 10 ``` ##### **`flat`** - **作用**:创建一个新的数组,并根据指定深度递归地将所有子数组元素拼接到新的数组中。 - **语法**:`arr.flat([depth])` - **示例**: ```javascript const arr1 = [0, 1, 2, [3, 4]]; console.log(arr1.flat()); // [0, 1, 2, 3, 4] const arr2 = [0, 1, [2, [3, [4, 5]]]]; console.log(arr2.flat(2)); // [0, 1, 2, 3, Array [4, 5]] console.log(arr2.flat(Infinity)); // [0, 1, 2, 3, 4, 5] ``` ##### **`flatMap()`** - 作用:结合了 `map` 和 `flat` 的功能,先对数组中的每个元素执行映射函数,然后将结果数组拍平一层。 - **语法**:`arr.flatMap(callback(currentValue[, index[, array]])[, thisArg])` - **示例**: ```javascript const nested = [[1], [2], [3]]; const flat = nested.flatMap(arr => arr); // [1,2,3] const arr = [1, 2, 3]; const result = arr.flatMap(x => [x, x * 2]); console.log(result); // [1, 2, 2, 4, 3, 6] ``` #### **3.6. 排序** ##### **`sort()`** - **作用**:对数组进行排序,默认按字符串顺序排序。 - **示例**: ```javascript const arr = [3, 1, 4, 2]; arr.sort(); // arr => [1, 2, 3, 4] (注意:默认按字符串排序) ``` - ##### **按数值排序**: ```javascript const arr = [3, 1, 4, 2]; arr.sort((a, b) => a - b); // arr => [1, 2, 3, 4] ``` #### **3.7. 合并与分割** ##### **`concat()`** - **作用**:合并两个或多个数组,返回新数组。 - **示例**: ```javascript const arr1 = [1, 2]; const arr2 = [3, 4]; const newArr = arr1.concat(arr2); // newArr => [1, 2, 3, 4] ``` ##### **`slice()`** - **作用**:提取数组的一部分,返回新数组,不修改原数组。 - **语法**:`arr.slice(start, end)`(`end` 不包含)。 - **示例**: ```javascript const arr = [1, 2, 3, 4]; const newArr = arr.slice(1, 3); // newArr => [2, 3] ``` ##### **`split()`(字符串转数组)** - **作用**:将字符串分割为数组。 - **示例**: ```javascript const str = 'a,b,c'; const arr = str.split(','); // arr => ['a', 'b', 'c'] ``` ##### **`join()`(数组转字符串)** - **作用**:将数组元素连接为字符串。 - **示例**: ```javascript const arr = ['a', 'b', 'c']; const str = arr.join('-'); // str => 'a-b-c' ``` #### **3.8. 判断数组** ##### **`isArray()`** - **作用**:判断一个对象是否为数组。 - **示例**: ```javascript Array.isArray([1, 2, 3]); // true Array.isArray({}); // false ``` #### **3.9. 其他常用方法** ##### **`includes()`** - **作用**:判断数组是否包含某个值,返回布尔值。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.includes(2); // true ``` ##### **`reverse()`** - **作用**:反转数组。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.reverse(); // arr => [3, 2, 1] ``` ##### **`every()`** - **作用**:判断数组中所有元素是否满足条件。 - **示例**: ```javascript const arr = [2, 4, 6]; arr.every(item => item % 2 === 0); // true ``` ##### **`some()`** - **作用**:判断数组中是否存在至少一个满足条件的元素。 - **示例**: ```javascript const arr = [1, 2, 3]; arr.some(item => item % 2 === 0); // true ``` ##### 解构赋值 ```javascript const [first, second, ...rest] = [1,2,3,4]; console.log(first); // 1 console.log(rest); // [3,4] ``` #### 3.10.数组拷贝 ##### 3.10.1. 浅拷贝 - **`slice()`** - **作用**:创建一个新数组,包含原数组的元素(从开始索引到结束索引,但不包括结束索引)。 - **语法**:`arr.slice([start], [end])` - **示例**: ```javascript const arr = [1, 2, 3, 4]; const shallowCopy = arr.slice(); console.log(shallowCopy); // [1, 2, 3, 4] ``` - **局限性**:只拷贝第一层,嵌套对象的引用仍然共享。 - **展开运算符 (`...`)** - **作用**:将数组展开为新数组。 - **语法**:`const newArr = [...arr]` - **示例**: ```javascript const arr = [1, 2, 3, 4]; const shallowCopy = [...arr]; console.log(shallowCopy); // [1, 2, 3, 4] ``` - **局限性**:同样只拷贝第一层。 - **`concat()`** - **作用**:合并数组并返回新数组。 - **语法**:`arr.concat()` - **示例**: ```javascript const arr = [1, 2, 3, 4]; const shallowCopy = arr.concat(); console.log(shallowCopy); // [1, 2, 3, 4] ``` - **局限性**:只拷贝第一层。 ##### **3.10.2. 深拷贝** - **`JSON.parse(JSON.stringify())`** - **作用**:将数组转换为 JSON 字符串,再解析为新数组。 - **语法**:`JSON.parse(JSON.stringify(arr))` - **示例**: ```javascript const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = JSON.parse(JSON.stringify(arr)); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]] ``` - **局限性**: - 无法处理函数、`undefined`、`Date`、`Map`、`Set` 等特殊对象。 - 无法处理循环引用。 - **递归实现深拷贝** - **作用**:手动递归拷贝数组及其嵌套元素。 - **实现**: ```javascript function deepClone(obj, hash = new WeakMap()) { if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const result = Array.isArray(obj) ? [] : {}; hash.set(obj, result); for (const key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key], hash); } } return result; } const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = deepClone(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]] ``` - **优点**:支持复杂对象和循环引用。 - **缺点**:实现复杂,性能较差。 - **Lodash 的 `_.cloneDeep()`** - **作用**:使用 Lodash 库实现深拷贝。 - **语法**:`_.cloneDeep(arr)` - **示例**: ```javascript const _ = require('lodash'); const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = _.cloneDeep(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]] ``` - **优点**:功能强大,支持复杂对象和循环引用,性能较好。 - **缺点**:需要引入外部库。 - **`structuredClone()`** - **作用**:使用现代浏览器的 `structuredClone` API。 - **语法**:`structuredClone(arr)` - **示例**: ```javascript const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = structuredClone(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]] ``` - **优点**:简单易用,支持多种数据类型,性能较好。 - **缺点**:不支持函数、`Symbol` 等某些特殊类型,浏览器兼容性有限。 #### 3.11.数组去重 - **使用 `Set`**: ```javascript const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // [1, 2, 3, 4, 5] ``` - **使用 `filter` 和 `indexOf`**: ```javascript const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.filter((item, index, self) => self.indexOf(item) === index); console.log(uniqueArr); // [1, 2, 3, 4, 5] ``` - **使用 `reduce`**: ```javascript const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.reduce((acc, item) => { if (!acc.includes(item)) { acc.push(item); } return acc; }, []); console.log(uniqueArr); // [1, 2, 3, 4, 5] ``` #### 3.12**性能优化注意事项** 1. **`push` 和 `pop`**:O(1) 时间复杂度,效率高。 2. **`unshift` 和 `shift`**:O(n) 时间复杂度,效率较低,尽量避免在大数据量时使用。 3. **`splice`**:性能取决于删除/插入的位置和数量,尽量避免频繁使用。 4. **`map` 和 `filter`**:遍历整个数组,复杂度为 O(n),适合中小规模数据。 5. **修改方法**:`push`, `pop`, `shift`, `unshift`, `splice`, `reverse`, `sort` 会改变原数组。 6. **安全方法**:`map`, `filter`, `slice`, `concat` 返回新数组。 7. **`sort()` 的默认行为**:默认按字符串排序,需传入比较函数进行数值或自定义排序。 8. `slice()` 和展开运算符 `([...arr])` 仅拷贝一层,嵌套对象仍为引用。 --- ### 4.高阶函数 #### 4.1.定义 高阶函数指: - **接收函数作为参数**(如 `map`、`filter`)。 ```js // 示例:回调函数 function repeat(n, callback) { for (let i = 0; i < n; i++) { callback(i); } } repeat(3, (index) => console.log(`Iteration ${index}`)); // 输出:Iteration 0, Iteration 1, Iteration 2 ``` - **返回函数作为结果**(如柯里化、闭包)。 ```javascript // 示例:闭包 function createCounter() { let count = 0; return function() { return count++; }; } const counter = createCounter(); console.log(counter()); // 0 console.log(counter()); // 1 ``` - 或两者兼具。 #### 4.2.高阶函数用法 ##### 4.2.1 柯里化 将多参数函数转换为单参数函数链: ```javascript function curryAdd(a) { return function(b) { return a + b; }; } const add5 = curryAdd(5); console.log(add5(3)); // 8 ``` ##### 4.2.2函数组合 组合多个函数为一个函数: ```javascript function compose(f, g) { return function(x) { return f(g(x)); }; } const uppercase = str => str.toUpperCase(); const reverse = str => str.split('').reverse().join(''); const reverseUpper = compose(uppercase, reverse); console.log(reverseUpper("hello")); // "OLLEH" ``` ##### **4.2.3.装饰器模式** 动态增强函数功能: ```javascript function logger(fn) { return function(...args) { console.log("Calling function with", args); const result = fn.apply(this, args); console.log("Result:", result); return result; }; } const add = logger((a, b) => a + b); add(2, 3); // 输出日志并返回5 ``` #### 4.3.闭包 **闭包(Closure)** 是一个函数与其**词法作用域(Lexical Environment)** 的组合。它允许函数访问并操作其外部函数的变量,即使外部函数已经执行完毕。 ##### 4.3.1.工作原理 - **词法作用域与执行上下文** - 词法作用域:函数的作用域由其定义的位置决定。例如: ```javascript function outer() { const outerVar = '外层变量'; function inner() { console.log(outerVar); // 引用外层变量 } return inner; } const closure = outer(); closure(); // 输出:外层变量 ``` - `inner` 函数在定义时“记住”了 `outer` 的作用域,即使 `outer` 已执行完毕,`inner` 仍能访问 `outerVar`。 - **词法环境(Lexical Environment)** - 词法环境 由两部分组成: - **环境记录(Environment Record)**:存储变量、函数声明等。 - **外层环境引用(Outer Environment Reference)**:指向父级作用域。 - 闭包的持久化: - 当外部函数执行完毕后,如果内部函数被外部引用,其词法环境不会被垃圾回收机制释放,从而形成闭包。 - **垃圾回收机制** - JavaScript 的垃圾回收机制会回收不再被引用的变量和对象。 - **闭包的内存问题**:如果闭包引用了大量外部变量且长期存在,可能导致内存泄漏。 ##### 4.3.2.应用场景 - **数据封装与私有变量** - 模拟私有变量: ```javascript function Counter() { let count = 0; // 私有变量 return { increment: () => count++, get: () => count }; } const counter = Counter(); console.log(counter.get()); // 0 counter.increment(); console.log(counter.get()); // 1 ``` - `count` 是外部函数 `Counter` 的局部变量,通过闭包被内部方法访问,外部无法直接修改。 - **保存状态(持续化变量)** - 计数器示例: ```javascript function createCounter() { let count = 0; return () => count++; } const counter = createCounter(); console.log(counter()); // 0 console.log(counter()); // 1 ``` - `count` 的值在每次调用时被保留,形成“持续状态”。 - **回调函数与异步编程** - 异步操作中保存上下文: ```javascript function asyncTask(data) { setTimeout(() => { console.log(`处理数据: ${data}`); }, 1000); } asyncTask("Hello"); // 1秒后输出 "处理数据: Hello" ``` - `setTimeout` 的回调函数通过闭包访问了外部函数 `asyncTask` 的参数 `data`。 ### 5.解构操作 #### 5.1.数组结构 - **基本用法** ```javascript const arr = [1, 2, 3]; const [a, b, c] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 ``` - **跳过元素** ```javascript //你可以通过在解构模式中留空来跳过数组中的某些元素。 const arr = [1, 2, 3, 4, 5]; const [a, , b, , c] = arr; console.log(a); // 1 console.log(b); // 3 console.log(c); // 5 ``` - **默认值** ```javascript //如果数组中的某些元素不存在,你可以为变量提供默认值。 const arr = [1, 2]; const [a, b, c = 3] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 ``` - **嵌套解构** ```javascript const arr = [1, [2, 3], 4]; const [a, [b, c], d] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(d); // 4 ``` - **剩余参数** ```javascript const [head, ...tail] = [1, 2, 3, 4]; console.log(head); // 1 console.log(tail); // [2, 3, 4] ``` #### 5.2.对象解构 - **基本用法** ```javascript const obj = { a: 1, b: 2, c: 3 }; const { a, b, c } = obj; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 ``` - **重命名变量** 你可以为解构的属性指定不同的变量名。 ```javascript const obj = { a: 1, b: 2 }; const { a: x, b: y } = obj; console.log(x); // 1 console.log(y); // 2 ``` - **默认值** 如果对象中没有某个属性,你可以为变量提供默认值。 ```javascript const obj = { a: 1 }; const { a, b = 2 } = obj; console.log(a); // 1 console.log(b); // 2 ``` - **嵌套解构** 对象解构支持嵌套结构。 ```javascript const obj = { a: 1, b: { c: 2, d: 3 }, e: 4 }; const { a, b: { c, d }, e } = obj; console.log(a); // 1 console.log(c); // 2 console.log(d); // 3 console.log(e); // 4 ``` - **剩余参数** ```javascript const { id, ...rest } = { id: 1, name: 'Bob', age: 25 }; console.log(rest); // { name: 'Bob', age: 25 } ``` #### 5.3.函数参数解构 ```javascript // 对象解构 function printUser({ name, age }) { console.log(`Name: ${name}, Age: ${age}`); } printUser({ name: 'Alice', age: 30 }); // Name: Alice, Age: 30 // 数组解构 function sum([a, b]) { return a + b; } console.log(sum([1, 2])); // 3 ``` #### 5.4.复杂嵌套结构 ```javascript const data = { user: { name: "Bob", address: { city: "New York" } }, hobbies: ["reading", "coding"] }; // 解构嵌套对象 const { user: { name, address: { city } }, hobbies: [firstHobby, ...otherHobbies] } = data; console.log(name, city); // "Bob" "New York" console.log(firstHobby, otherHobbies); // "reading" ["coding"] ``` #### 5.5.应用场景 - **交换变量值** 通过解构实现变量交换: ```javascript let x = 1, y = 2; [x, y] = [y, x]; // x=2, y=1 ``` - **字符串解构** 将字符串视为字符数组进行解构: ```javascript const [a, b, c] = 'cat'; // a='c', b='a', c='t' ``` - **计算属性名** 用表达式作为属性名: ```javascript const key = 'age'; const obj = { age: 25 }; const { [key]: userAge } = obj; // userAge=25 ``` - **从函数返回多个值** ```javascript function getCoordinates() { return { x: 10, y: 20 }; } const { x, y } = getCoordinates(); console.log(x, y); // 10 20 ``` - **忽略不需要的值** ```javascript const [onlyFirst, , third] = [1, 2, 3]; console.log(onlyFirst, third); // 1 3 ``` - **解构与模块导入** ```javascript // mathUtils.js export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; // main.js import { add, subtract } from "./mathUtils.js"; console.log(add(5, 3)); // 8 ``` ### 6.JSON操作 #### 6.1.`JSON.stringify()` 将对象或数组转为字符串,支持过滤、转换和格式化。 - 语法:`JSON.stringify(value[, replacer[, space]])` - **`value`**: 要序列化的对象。 - **`replacer`**(可选):函数或数组,用于过滤或转换属性。 - **`space`**(可选):格式化缩进(数字或字符串)。 - 示例 ```javascript const obj = { name: "Alice", age: 25, date: new Date() }; // 基础序列化 console.log(JSON.stringify(obj)); // '{"name":"Alice","age":25,"date":"2023-10-01T00:00:00.000Z"}' // 过滤属性(仅保留 name 和 age) console.log(JSON.stringify(obj, ["name", "age"])); // '{"name":"Alice","age":25}' // 使用 replacer 函数 console.log(JSON.stringify(obj, (key, value) => { if (key === "date") return value.toISOString(); // 格式化日期 return value; })); //用于指定缩进空格数,使输出的 JSON 字符串更易读。 const obj = { name: 'Alice', age: 30 }; const jsonString = JSON.stringify(obj, null, 2); console.log(jsonString); // { // "name": "Alice", // "age": 30 // } ``` - 循环引用问题:默认无法处理循环引用,会导致错误。可以通过 `replacer` 函数来处理。 ```javascript const obj = { a: 1 }; obj.b = obj; try { JSON.stringify(obj); // 抛出错误 } catch (e) { console.error('Error:', e.message); } // 使用 replacer 处理循环引用 function replacer(key, value) { if (value === obj) return '[Circular]'; return value; } console.log(JSON.stringify(obj, replacer)); // '{"a":1,"b":"[Circular]"}' ``` - **`JSON.stringify()` 会忽略函数、undefined和 `Symbol` 键**: ```javascript const obj = { name: 'Alice', greet: function() { console.log('Hello!'); }, id: Symbol('123') }; console.log(JSON.stringify(obj)); // '{"name":"Alice"}' ``` #### 6.2.`JSON.parse()` 将 JSON 字符串转换为 JavaScript 对象或数组。 - **语法**:`JSON.parse(text[, reviver])` - **`text`**:要解析的 JSON 字符串。 - **`reviver`**(可选):函数,用于在解析后转换结果(如类型转换或数据校验)。 - 示例 ```javascript const jsonString = '{"name":"Alice","age":30}'; const obj = JSON.parse(jsonString); console.log(obj); // { name: 'Alice', age: 30 } //reviver const jsonString = '{"name":"Alice","age":30,"email":"alice@example.com"}'; const obj = JSON.parse(jsonString, (key, value) => { if (key === 'email') return value.toUpperCase(); return value; }); console.log(obj); // { name: 'Alice', age: 30, email: 'ALICE@EXAMPLE.COM' } //如果 JSON 字符串格式不正确,JSON.parse() 会抛出错误。 const invalidJson = '{"name": "Alice",}'; // 额外的逗号 try { JSON.parse(invalidJson); } catch (e) { console.error('Error:', e.message); // Error: Unexpected token } at position 15 } ``` ### 7.集合 #### 7.1.Map 用于键值对存储,键可以是任何数据类型(包括对象、函数等)。保持插入顺序。 ##### 7.1.1.方法 | 方法 | 功能描述 | | -------------------- | ------------------------------------------------ | | `new Map()` | 创建一个空的 `Map`。 | | `.set(key, value)` | 设置键值对,若键存在则更新值,返回 `Map` 本身。 | | `.get(key)` | 获取指定键的值,若不存在返回 `undefined`。 | | `.has(key)` | 检查是否存在指定键。 | | `.delete(key)` | 删除指定键的键值对,返回是否删除成功。 | | `.clear()` | 清空所有键值对。 | | `.keys()` | 返回一个包含所有键的迭代器。 | | `.values()` | 返回一个包含所有值的迭代器。 | | `.entries()` | 返回一个包含 `[key, value]` 数组的迭代器。 | | `.forEach(callback)` | 遍历所有键值对,回调参数为 `(value, key, map)`。 | **示例** ```javascript const map = new Map([ ["name", "Alice"], [42, "The Answer"] ]); // 添加/删除元素 map.set("age", 25); // Map(3) { "name" → "Alice", 42 → "The Answer", "age" → 25 } map.delete("name"); // true → 移除键 "name" // 查询与遍历 map.get(42); // "The Answer" map.has("age"); // true map.size; // 2 // 遍历 map.forEach((value, key) => console.log(`${key}: ${value}`)); //使用对象 const user = { id: 1 }; const userMap = new Map(); userMap.set(user, "Alice"); // 键是对象 console.log(userMap.get(user)); // "Alice" //动态的键值对 const cache = new Map(); cache.set("key1", "value1"); cache.set(123, { data: "test" }); // 对象转 Map const obj = { a: 1, b: 2 }; const mapFromObj = new Map(Object.entries(obj)); // Map { "a" → 1, "b" → 2 } // Map 转对象 const objFromMap = Object.fromEntries(mapFromObj); // { a: 1, b: 2 } //Map转数组 const arr = Array.from(map); ``` ##### 7.1.2.和Object比较 | 特性 | `Map` | 对象(Object) | | -------- | ---------------------------- | ----------------------------------- | | 键的类型 | 任意类型(包括对象、函数等) | 仅字符串或符号(Symbol) | | 遍历顺序 | 保持插入顺序 | 无保证(ES5 及之前) | | 大小查询 | `map.size` | 需手动统计或 `Object.keys().length` | | 性能 | 更适合频繁增删改的场景 | 适合简单的键值存储 | #### 7.2.Set 集合(Set)是一种数据结构,用于存储唯一的值。集合中的元素是唯一的,这意味着集合中不能有重复的值。集合提供了多种方法来添加、删除和检查元素。 ##### 7.2.1.基本方法 | 方法 | 功能描述 | | -------------------- | ---------------------------------------------------------- | | `new Set()` | 创建一个空的 `Set`。 | | `.add(value)` | 向集合中添加一个元素,若已存在则不操作,返回 `Set` 本身。 | | `.delete(value)` | 从集合中删除指定元素,返回是否删除成功(`true`/`false`)。 | | `.has(value)` | 检查集合中是否存在指定元素,返回布尔值。 | | `.clear()` | 清空集合中的所有元素。 | | `.size` | 返回集合中元素的数量。 | | `.forEach(callback)` | 遍历集合中的每个元素,执行回调函数。也可以用`for...of` | | `.values()` | 返回一个包含集合中所有值的迭代器。 | ```javascript // 通过数组初始化 const fruits = new Set(["apple", "banana", "cherry"]); // 逐步添加元素 const numbers = new Set(); numbers.add(1).add(2).add(3); // 链式调用 // 通过变量添加元素 const name = "Alice"; const users = new Set(); users.add(name); // 添加字符串 users.add({ id: 1 }); // 添加对象 //遍历 const mySet = new Set([1, 2, 3]); for (const value of mySet) { console.log(value); } // 1 // 2 // 3 const mySet = new Set([1, 2, 3]); mySet.forEach(value => { console.log(value); }); // 1 // 2 // 3 //集合转数组 const mySet = new Set([1, 2, 3]); const arr = Array.from(mySet); // 或 [...mySet] console.log(arr); // [1, 2, 3] ``` - **`NaN`**:虽然 `NaN !== NaN`,但 `Set` 中只会存储一个 `NaN`。 - **`null`/`undefined`**:会被视为唯一值,但多次添加不会重复。 ##### 7.2.2.高级方法 - **`union()`**:合并两个 `Set`,去重后返回新 `Set`。 - **`intersection()`**:返回两个 `Set` 的交集。 - **`difference()`**:返回在第一个 `Set` 中但不在第二个中的元素。 - **`symmetricDifference()`**:返回两个 `Set` 的非交集元素。 ```javascript const setA = new Set([1, 2, 3]); const setB = new Set([3, 4, 5]); // 合并 const unionSet = setA.union(setB); // {1, 2, 3, 4, 5} // 交集 const intersectionSet = setA.intersection(setB); // {3} // 差集 const differenceSet = setA.difference(setB); // {1, 2} // 对称差集 const symDiffSet = setA.symmetricDifference(setB); // {1, 2, 4, 5} ``` ##### 7.2.3.应用 - **去重与统计频率** ```javascript const arr = [1, 2, 2, 3, 3, 3]; const frequency = [...new Set(arr)].reduce((acc, num) => { acc[num] = arr.filter(x => x === num).length; return acc; }, {}); // {1:1, 2:2, 3:3} ``` ### 8.日期处理 #### 8.1. 创建日期对象 - **当前日期和时间**: ```javascript const now = new Date(); console.log(now); // 当前日期和时间 ``` - **指定日期和时间**: ```javascript const specificDate = new Date(2023, 9, 15, 12, 30, 0); // 年, 月(0-11), 日, 时, 分, 秒 console.log(specificDate); // 2023-10-15T12:30:00 ``` - **日期字符串**: ```javascript const dateString = new Date('2023-10-15T12:30:00'); console.log(dateString); // 2023-10-15T12:30:00 ``` #### 8.2. 获取日期和时间 - **获取年份**: ```javascript const year = new Date().getFullYear(); console.log(year); // 2023 ``` - **获取月份**(0-11): ```javascript const month = new Date().getMonth(); console.log(month); // 9 (十月) ``` - **获取日期**: ```javascript const day = new Date().getDate(); console.log(day); // 15 ``` - **获取星期几**(0-6,0 表示星期日): ```javascript const dayOfWeek = new Date().getDay(); console.log(dayOfWeek); // 0-6 ``` - **获取小时**: ```javascript const hours = new Date().getHours(); console.log(hours); // 0-23 ``` - **获取分钟**: ```javascript const minutes = new Date().getMinutes(); console.log(minutes); // 0-59 ``` - **获取秒数**: ```javascript const seconds = new Date().getSeconds(); console.log(seconds); // 0-59 ``` - **获取毫秒**: ```javascript const milliseconds = new Date().getMilliseconds(); console.log(milliseconds); // 0-999 ``` #### 3. 设置日期和时间 - **设置年份**: ```javascript const date = new Date(); date.setFullYear(2024); console.log(date.getFullYear()); // 2024 ``` - **设置月份**: ```javascript const date = new Date(); date.setMonth(11); // 11 表示 12 月 console.log(date.getMonth()); // 11 ``` - **设置日期**: ```javascript const date = new Date(); date.setDate(20); console.log(date.getDate()); // 20 ``` - **设置小时**: ```javascript const date = new Date(); date.setHours(15); console.log(date.getHours()); // 15 ``` - **设置分钟**: ```javascript const date = new Date(); date.setMinutes(30); console.log(date.getMinutes()); // 30 ``` - **设置秒数**: ```javascript const date = new Date(); date.setSeconds(45); console.log(date.getSeconds()); // 45 ``` - **设置毫秒**: ```javascript const date = new Date(); date.setMilliseconds(500); console.log(date.getMilliseconds()); // 500 ``` #### 8.4. 日期格式化 - **使用 `toLocaleDateString()`**: ```javascript const date = new Date(); console.log(date.toLocaleDateString()); // 2023/10/15 (格式取决于浏览器的本地设置) ``` - **自定义格式化**: ```javascript function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } const date = new Date(); console.log(formatDate(date)); // 2023-10-15 ``` - **使用 `Intl.DateTimeFormat`(推荐)** ```javascript const date = new Date(); const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZone: 'Asia/Shanghai' // 指定时区 }; console.log(new Intl.DateTimeFormat('zh-CN', options).format(date)); // "2023/12/25 10:30:00" ``` - **使用第三方库(如 `date-fns`)** ```javascript import { format } from 'date-fns'; import { zhCN } from 'date-fns/locale'; console.log(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: zhCN })); // "2023-12-25 10:30:00" ``` #### **8.5. 日期计算** - **计算两个日期之间的天数差**: ```javascript function daysBetween(date1, date2) { const diffTime = Math.abs(date2 - date1); return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } const date1 = new Date('2023-10-01'); const date2 = new Date('2023-10-15'); console.log(daysBetween(date1, date2)); // 14 ``` - **添加天数到日期**: ```javascript function addDays(date, days) { const newDate = new Date(date); newDate.setDate(newDate.getDate() + days); return newDate; } const date = new Date('2023-10-15'); const newDate = addDays(date, 5); console.log(newDate); // 2023-10-20 ``` - 时间戳 ```javascript const now = new Date(); const timestamp = now.getTime(); // 获取当前时间戳(毫秒) console.log(timestamp); // 例如:1712023102000 // 通过Date.now()快速获取时间戳 console.log(Date.now()); // 等同于new Date().getTime() ``` #### **8.6. 时区处理** - **获取 UTC 时间**: ```javascript const date = new Date(); console.log(date.toUTCString()); // Wed, 18 Oct 2023 04:30:00 GMT ``` - **获取本地时间**: ```javascript const date = new Date(); console.log(date.toLocaleString()); // 2023/10/15 下午12:30:00 (格式取决于浏览器的本地设置) ``` ### 10.事件 #### 10.1.Event对象 用户或浏览器触发的交互行为(如点击、键盘输入、页面加载等)。事件处理函数的参数 `event` 包含交互的详细信息: **常用属性** | 属性 | 描述 | | ------------------------- | ---------------------------------------- | | `event.type` | 事件类型(如 `"click"`)。 | | `event.target` | 触发事件的实际元素(原始目标)。 | | `event.currentTarget` | 当前处理事件的元素(绑定监听器的元素)。 | | `event.preventDefault()` | 阻止默认行为(如表单提交、链接跳转)。 | | `event.stopPropagation()` | 阻止事件冒泡/捕获。 | | `event.clientX/Y` | 鼠标事件的坐标(相对于视口)。 | **示例代码**: ```javascript button.addEventListener("click", (event) => { console.log("目标元素:", event.target); // 实际点击的元素 console.log("当前元素:", event.currentTarget); // 绑定事件的元素 event.preventDefault(); // 阻止默认行为(如表单提交) event.stopPropagation(); // 阻止事件冒泡 }); ``` #### 10.2.事件传播机制 事件传播分为三个阶段: 1. **捕获阶段(Capture Phase)**:事件从 `window` 向下传递到目标元素。 2. **目标阶段(Target Phase)**:事件到达目标元素。 3. **冒泡阶段(Bubble Phase)**:事件从目标元素向上传递回 `window`。 **示例**:点击嵌套元素 `div > p` 时的事件流顺序: ```javascript window → document → html → body → div → p(捕获阶段) p → div → body → html → document → window(冒泡阶段) ``` **事件委托:**利用事件冒泡机制,将事件监听器绑定到父元素,处理子元素的事件: ```html Item 1 Item 2 ``` ```javascript const parent = document.getElementById("parent"); parent.addEventListener("click", (event) => { if (event.target.tagName === "LI") { console.log("列表项被点击:", event.target.textContent); } }); ``` #### 10.3.自定义事件 ```javascript // 创建自定义事件 const customEvent = new CustomEvent("myEvent", { detail: { message: "Hello!" }, }); // 触发事件 document.dispatchEvent(customEvent); // 监听自定义事件 document.addEventListener("myEvent", (event) => { console.log("自定义事件触发:", event.detail.message); }); ``` #### 10.4.常用事件 | **事件类别** | **事件名称** | **触发时机** | **备注** | | :--------------: | :-----------: | :------------------------------------------------: | :------------------------------------------: | | **用户界面事件** | `click` | 鼠标点击元素时触发 | 最常用事件之一 | | | `dblclick` | 双击元素时触发 | 注意防止双击选中文本 | | | `contextmenu` | 右键点击元素时触发(默认弹出右键菜单) | 可用 `event.preventDefault()` 阻止默认行为 | | | `mousedown` | 鼠标按下时触发 | 常用于拖拽功能 | | | `mouseup` | 鼠标释放时触发 | 与 `mousedown` 配合使用 | | **焦点事件** | `focus` | 元素获得焦点时触发(如输入框点击、激活) | 不冒泡 | | | `blur` | 元素失去焦点时触发 | 不冒泡 | | | `focusin` | 元素获得焦点时触发(支持冒泡) | 可用于事件委托 | | | `focusout` | 元素失去焦点时触发(支持冒泡) | 同上 | | **鼠标事件** | `mouseover` | 鼠标进入元素或其子元素时触发 | 会冒泡 | | | `mouseout` | 鼠标离开元素或其子元素时触发 | 会冒泡 | | | `mouseenter` | 鼠标进入元素时触发(不检测子元素) | 不冒泡 | | | `mouseleave` | 鼠标离开元素时触发(不检测子元素) | 不冒泡 | | | `mousemove` | 鼠标在元素上移动时触发 | 高频触发,需注意性能 | | **键盘事件** | `keydown` | 按下键盘按键时触发(字符键和功能键) | 可获取 `event.key` 或 `event.keyCode` | | | `keypress` | 按下字符键时触发(已废弃,推荐用 `keydown`) | | | | `keyup` | 松开键盘按键时触发 | | | **表单事件** | `submit` | 表单提交时触发(如点击提交按钮) | 可阻止默认提交行为 | | | `change` | 表单元素值改变且失去焦点时触发(如输入框、下拉框) | 常用于实时验证 | | | `input` | 表单元素值改变时立即触发(无需失去焦点) | 实时性更强 | | | `reset` | 表单重置时触发 | | | **窗口事件** | `resize` | 浏览器窗口大小改变时触发 | 需节流处理高频触发 | | | `scroll` | 页面或元素滚动时触发 | 需优化性能 | | | `load` | 页面或图片等资源完全加载完成时触发 | 常用于 `window` 或 `` | | | `unload` | 页面卸载时触发(如关闭标签页) | 不推荐使用,存在兼容性问题 | | **拖放事件** | `dragstart` | 拖拽操作开始时触发 | 需设置元素为 `draggable="true"` | | | `dragover` | 拖拽元素在目标元素上方移动时触发 | 需调用 `event.preventDefault()` | | | `drop` | 拖拽元素在目标元素上释放时触发 | | | **剪贴板事件** | `copy` | 复制操作时触发 | 可修改剪贴板内容 | | | `cut` | 剪切操作时触发 | | | | `paste` | 粘贴操作时触发 | | | **资源加载事件** | `error` | 资源加载失败时触发(如图片、脚本) | | | **触摸事件** | `touchstart` | 手指触摸屏幕时触发 | 移动端常用 | | | `touchmove` | 手指在屏幕上滑动时触发 | 需调用 `event.preventDefault()` 防止页面滚动 | | | `touchend` | 手指离开屏幕时触发 | | ### 11.BOM #### 11.1.Window对象 代表浏览器窗口(全局对象) **常用属性** - `location`:访问当前窗口的 `Location` 对象。 - `history`:访问当前窗口的 `History` 对象。 - `navigator`:访问当前浏览器的 `Navigator` 对象。 - `screen`:访问当前屏幕的 `Screen` 对象。 - `document`:访问当前窗口的文档对象(DOM 根对象)。 - `innerWidth`/`innerHeight`:获取窗口内部宽度/高度(包含滚动条)。 - `outerWidth`/`outerHeight`:获取窗口外部宽度/高度(包含浏览器边框和工具栏)。 **常用方法** | 方法名 | 说明 | 示例 | | ---------------------------------- | ------------------------------------- | -------------------------------------------------------- | | `alert()` | 显示警告对话框 | `window.alert("提示信息");` | | `confirm()` | 显示确认对话框(返回布尔值) | `if (window.confirm("确定提交?")) { ... }` | | `prompt()` | 显示输入对话框(返回输入值或 `null`) | `let input = window.prompt("请输入");` | | `setTimeout()` | 设置定时器,延迟执行代码 | `setTimeout(() => { console.log("执行"); }, 1000);` | | `setInterval()` | 设置周期性定时器 | `setInterval(() => { console.log("每秒执行"); }, 1000);` | | `clearTimeout()`/`clearInterval()` | 清除定时器 | `clearTimeout(timerId);` | | `open()` | 打开新窗口或标签页 | `window.open("https://example.com");` | | `close()` | 关闭当前或指定窗口 | `window.close();` | | `resizeTo()` | 调整窗口大小 | `window.resizeTo(800, 600);` | | `moveTo()` | 移动窗口到指定坐标 | `window.moveTo(100, 100);` | | `scrollTo()`/`scrollBy()` | 滚动页面到指定位置 | `window.scrollTo(0, document.body.scrollHeight);` | #### 11.2.Navigator对象 浏览器对象 | **属性** | **描述** | | :------------------------ | :--------------------------- | | `navigator.appName` | 获取浏览器的名称 | | `navigator.appVersion` | 获取浏览器的平台和版本信息 | | `navigator.language` | 获取当前浏览器的语言 | | `navigator.userAgent` | 获取用户代理字符串 | | `navigator.cookieEnabled` | 获取浏览器是否启用cookie | | `navigator.onLine` | 获取浏览器是否处于在线模式 | | `navigator.platform` | 获取运行浏览器的操作系统平台 | | 方法名 | 说明 | | ---------------------------------- | ---------------------- | | `geolocation.getCurrentPosition()` | 获取用户地理位置 | | `vibrate()` | 触发设备振动(需权限) | | `sendBeacon()` | 异步发送小数据到服务器 | #### 11.3.Location 浏览器的地址栏信息 | 属性名 | 说明 | | -------------- | ---------------------------------------------------- | | `href` | 完整 URL(如 `https://example.com/path?query#hash`) | | `protocol` | URL 的协议(如 `https:`) | | `host` | 主机名 + 端口号(如 `example.com:8080`) | | `hostname` | 主机名(如 `example.com`) | | `port` | 端口号(如 `8080`) | | `pathname` | 路径部分(如 `/path`) | | `search` | 查询字符串(如 `?key=value`) | | `hash` | 锚点部分(如 `#section`) | | `origin` | 协议、主机和端口的组合(如 `https://example.com`) | | `searchParams` | URL 查询参数的 `URLSearchParams` 对象(ES6+) | **常用方法** | 方法名 | 说明 | | -------------- | ------------------------------ | | `assign(url)` | 加载新 URL(替换当前历史记录) | | `replace(url)` | 替换当前页面且不生成历史记录 | | `reload()` | 重新加载当前页面 | #### 11.4.History | **属性** | **描述** | | :--------------- | :------------------------- | | `history.length` | 返回历史浏览记录的当前长度 | | **方法** | **说明** | | :-------------------------------- | :---------------------------------------------------- | | `back()` | 返回上一页(等同于浏览器的后退按钮) | | `forward()` | 前进到下一页 | | `go(n)` | 跳转到指定历史记录索引(`0` 为当前页,`-1` 为上一页) | | `pushState(state, title, url)` | 无刷新添加历史记录条目(SPA 常用) | | `replaceState(state, title, url)` | 替换当前历史记录条目(无刷新) | #### 11.5.screen | 属性名 | 说明 | | ------------- | -------------------------- | | `availWidth` | 屏幕可用宽度(排除任务栏) | | `availHeight` | 屏幕可用高度(排除任务栏) | | `width` | 屏幕总宽度(含任务栏) | | `height` | 屏幕总高度(含任务栏) | | `colorDepth` | 屏幕颜色深度(位数) | #### 11.6.Document | **方法** | **描述** | **示例代码** | | :------------------------------------ | :-------------------------------------------------------- | :----------------------------------------------------------- | | `getElementById(id)` | 根据元素的 ID 获取元素。 | `const element = document.getElementById('myId');` | | `querySelector(selector)` | 使用 CSS 选择器获取第一个匹配的元素。 | `const element = document.querySelector('#myId');` | | `querySelectorAll(selector)` | 使用 CSS 选择器获取所有匹配的元素,返回一个静态节点列表。 | `const elements = document.querySelectorAll('.myClass');` | | `getElementsByClassName(name)` | 根据类名获取元素,返回一个 HTML 集合。 | `const elements = document.getElementsByClassName('myClass');` | | `getElementsByTagName(name)` | 根据标签名获取元素,返回一个 HTML 集合。 | `const elements = document.getElementsByTagName('div');` | | `createElement(tagName)` | 创建一个新的 HTML 元素。 | `const newElement = document.createElement('div');` | | `createTextNode(text)` | 创建一个新的文本节点。 | `const textNode = document.createTextNode('Hello, World!');` | | `appendChild(node)` | 将一个节点添加到父节点的子节点列表的末尾。 | `parentElement.appendChild(newElement);` | | `insertBefore(node, referenceNode)` | 在参考节点之前插入一个节点。 | `parentElement.insertBefore(newElement, referenceNode);` | | `removeChild(node)` | 从父节点中移除一个子节点。 | `parentElement.removeChild(childElement);` | | `replaceChild(newNode, oldNode)` | 用新节点替换旧节点。 | `parentElement.replaceChild(newNode, oldNode);` | | `addEventListener(type, listener)` | 为元素添加事件监听器。 | `element.addEventListener('click', function() { console.log('Clicked!'); });` | | `removeEventListener(type, listener)` | 移除元素的事件监听器。 | `element.removeEventListener('click', myFunction);` | | `getAttribute(name)` | 获取元素的指定属性值。 | `const value = element.getAttribute('href');` | | `setAttribute(name, value)` | 设置元素的指定属性值。 | `element.setAttribute('href', 'https://example.com');` | | `removeAttribute(name)` | 移除元素的指定属性。 | `element.removeAttribute('href');` | | `innerHTML` | 获取或设置元素的 HTML 内容。 | `element.innerHTML = 'New content';` | | `textContent` | 获取或设置元素的文本内容(不解析 HTML)。 | `element.textContent = 'New text';` | | `style` | 获取或设置元素的样式。 | `element.style.color = 'red';` | | `classList` | 操作元素的类列表。 | `element.classList.add('myClass');` | | `getComputedStyle(element)` | 获取元素的计算样式。 | `const style = window.getComputedStyle(element);` | **输出流** | **方法** | **描述** | **示例代码** | | -------------------- | ------------------------------------------------------ | ----------------------------------------------- | | `document.write()` | 向文档写入 HTML 内容(**慎用**,仅在页面加载前使用)。 | `document.write("Hello");` | | `document.writeln()` | 写入 HTML 内容并换行。 | `document.writeln("Line 1 Line 2");` | **示例代码** ```javascript // 通过 ID 获取元素 const elementById = document.getElementById('myId'); // 通过类名获取元素 const elementsByClass = document.getElementsByClassName('myClass'); // 通过标签名获取元素 const elementsByTag = document.getElementsByTagName('div'); // 使用 CSS 选择器获取元素 const elementBySelector = document.querySelector('#myId'); const elementsBySelector = document.querySelectorAll('.myClass'); const href = element.getAttribute("href"); // 获取属性值 // 创建新元素 const newDiv = document.createElement('div'); newDiv.textContent = 'New content'; // 添加到文档 document.body.appendChild(newDiv); // 在指定位置插入元素 const referenceElement = document.getElementById('reference'); referenceElement.parentNode.insertBefore(newDiv, referenceElement); element.setAttribute("title", "点击查看详情"); // 设置属性 element.removeAttribute("data-old"); // 删除属性 element.checked = true; // 复选框选中状态 element.disabled = false; // 启用按钮 // 添加点击事件监听器 const button = document.getElementById('myButton'); button.addEventListener('click', function() { console.log('Button clicked!'); }); // 移除事件监听器 function handleClick() { console.log('Button clicked!'); } button.removeEventListener('click', handleClick); ``` [post cid="10" cover="" size=""/] Javascript进阶1.字符串操作1.1.基本方法创建字符串// 字面量 const str1 = "Hello World"; // 构造函数 const str2 = new String("Hello World"); // 模板字符串(ES6) const name = "Alice"; const greeting = `Hello, ${name}!`; // "Hello, Alice!"基本属性与方法const str = "JavaScript"; console.log(str.length); // 字符串长度:10 console.log(str[0]); // 访问字符:'J' console.log(str.charAt(5)); // 'S'(索引从0开始) console.log(str.localeCompare("Java")); // 比较字符串:"JavaScript" > "Java" → 1查找与定位方法描述示例indexOf(searchValue)返回子字符串首次出现的索引,未找到返回 -1"apple".indexOf("p") → 1lastIndexOf(searchValue)返回子字符串最后一次出现的索引"apple".lastIndexOf("p") → 2includes(searchValue)是否包含子字符串(ES6)"apple".includes("app") → truestartsWith(searchValue)是否以指定字符串开头(ES6)"apple".startsWith("ap") → trueendsWith(searchValue)是否以指定字符串结尾(ES6)"apple".endsWith("le") → true截取与拼接方法描述示例concat(str1, str2)合并多个字符串"Hello".concat(" ", "World") → "Hello World"slice(start, end)截取子字符串(支持负数索引)"apple".slice(1, -1) → "ppl"substring(start, end)类似 slice,但负数索引会被视为 0"apple".substring(1, 3) → "pp"substr(start, length)从指定位置开始截取指定长度的字符串"apple".substr(1, 3) → "ppl"替换与分割方法描述示例replace(searchValue, newValue)替换子字符串(仅第一次匹配)"apple".replace("p", "x") → "axple"split(separator)按分隔符拆分为数组"a,b,c".split(",") → ["a", "b", "c"]trim()去除首尾空白字符" apple ".trim() → "apple"trimStart()/trimEnd()去除首/尾空白字符" apple ".trimStart() → "apple "大小写转换方法描述示例toLowerCase()转换为小写"Apple".toLowerCase() → "apple"toUpperCase()转换为大写"apple".toUpperCase() → "APPLE"1.2.高阶操作1. 字符串遍历const str = "hello"; for (let char of str) { console.log(char); // 分别输出 h e l l o }统计字符出现次数function countChars(str) { const counts = {}; for (const char of str) { counts[char] = (counts[char] || 0) + 1; } return counts; } console.log(countChars("aabbc")); // { a: 2, b: 2, c: 1 }解析 URL 参数function getUrlParams(url) { const params = {}; const parser = new URL(url); parser.searchParams.forEach((value, key) => { params[key] = value; }); return params; } const url = "https://example.com?name=Alice&age=25"; console.log(getUrlParams(url)); // { name: 'Alice', age: '25' }模板字符串(ES6)const price = 9.99; const message = `Price: $${price.toFixed(2)}`; // "Price: $9.99"1.3.正则表达式1.3.1.创建正则字面量const regex = /hello/; // 基础正则 const regexWithFlags = /\d+/ig; // 添加修饰符(i: 忽略大小写,g: 全局匹配)构造函数const regex = new RegExp("hello", "g"); // 动态创建正则修饰符修饰符作用i忽略大小写g全局匹配(找到所有匹配)m多行匹配(^和$匹配每行)s允许.匹配换行符1.3.2.常用符号元字符:元字符作用示例.匹配任意单个字符(除换行)/a.c/ 匹配 "abc", "a2c"^匹配字符串开头/^hello/ 匹配以"hello"开头$匹配字符串结尾/world$/ 匹配以"world"结尾*匹配前面字符 0 次或多次/ab*/ 匹配 "a", "ab", "abbb"+匹配前面字符 1 次或多次/ab+/ 匹配 "ab", "abbb"?匹配前面字符 0 次或 1 次/colou?r/ 匹配 "color"或"colour"{n}匹配前面字符恰好 n 次/a{3}/ 匹配 "aaa"{n,}匹配前面字符至少 n 次/a{2,}/ 匹配 "aa", "aaa"{n,m}匹配前一个字符 n 到 m 次/a{2,4}/ → 匹配 "aa"~"aaaa"()分组,捕获匹配内容/(ab)+/ → 匹配 "ab"、"abab"字符类:表达式作用\d匹配数字(0-9)\D匹配非数字\w匹配字母、数字、下划线\W匹配非字母、数字、下划线\s匹配空白字符(空格、换行等)[abc]匹配 a、b 或 c[^abc]匹配非 a、b、c 的字符1.3.3.常用方法RegExp.prototype.test()检查字符串是否匹配正则表达式。const regex = /Hello/; console.log(regex.test('Hello, World!')); // true console.log(regex.test('HELLO')); // false未匹配 大小写RegExp.prototype.exec()执行搜索匹配,返回匹配结果或 null。const regex = /Hello/; const result = regex.exec('Hello, World!'); console.log(result); // ['Hello', index: 0, input: 'Hello, World!', groups: undefined]match()在字符串中执行搜索匹配,返回匹配结果数组或 null。const str = 'Hello, World!'; console.log(str.match(/Hello/)); // ['Hello', index: 0, input: 'Hello, World!', groups: undefined]matchAll()返回所有匹配项的迭代器。const str = 'Hello, Hello!'; const regex = /Hello/g; console.log(Array.from(str.matchAll(regex))); // [['Hello', index: 0], ['Hello', index: 7]]search()返回第一个匹配项的索引。const str = 'Hello, World!'; console.log(str.search(/World/)); // 7replace()替换字符串中的匹配项。const str = 'Hello, World!'; console.log(str.replace(/World/, 'Alice')); // 'Hello, Alice!'split()将字符串拆分为数组。const str = 'Hello, World!'; console.log(str.split(/, /)); // ['Hello', 'World!']1.3.4.进阶使用捕获组与非捕获组// 捕获组(可通过 `exec` 或 `matchAll` 获取分组内容) const regex = /(a)(b)/; const str = "ab"; const result = regex.exec(str); console.log(result[1]); // "a"(第一个捕获组) console.log(result[2]); // "b"(第二个捕获组) // 非捕获组(仅分组不捕获) const regex2 = /(?:a)(b)/;前瞻(Lookahead)与后顾(Lookbehind)也叫预查断言// 正向前瞻:匹配后面跟着特定字符的内容 const str = "apple123"; console.log(str.match(/\d+(?=\.)/)); // null(无小数点) console.log("apple123.45".match(/\d+(?=\.)/)); // "123" // 反向前瞻:匹配前面是特定字符的内容 console.log("apple123".match(/(?<=apple)\d+/)); // "123" // 正向后顾:匹配前面是特定字符的内容 console.log("apple123".match(/(?<=apple)\d+/)); // "123"贪婪与非贪婪匹配const str = "<div>Hello</div><div>World</div>"; // 贪婪匹配(默认) console.log(str.match(/<div>.*<\/div>/)); // "<div>Hello</div><div>World</div>" // 非贪婪匹配(添加 ?) console.log(str.match(/<div>.*?<\/div>/g)); // ["<div>Hello</div>", "<div>World</div>"]数据提取const text = "Price: $19.99, Quantity: 5"; // 提取价格 const priceMatch = text.match(/\$\d+\.\d+/); console.log(priceMatch[0]); // "$19.99" // 提取所有数字 const numbers = text.match(/\d+/g); console.log(numbers); // ["19", "99", "5"] //提取URL const url = 'https://example.com?name=Alice&age=30'; const params = url.split('?')[1].split('&').reduce((acc, param) => { const [key, value] = param.split('='); acc[key] = value; return acc; }, {}); console.log(params); // { name: 'Alice', age: '30' }文本替换const str = "Hello WORLD"; // 替换所有大写字母为小写 const newStr = str.replace(/[A-Z]/g, (match) => match.toLowerCase()); console.log(newStr); // "hello world"1.3.5.常用正则表达式场景正则表达式说明邮箱验证^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$基础邮箱验证(允许字母、数字、点、下划线、百分号、加号、减号)。 ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$更严格验证(限制域名长度为 2~6 位)。手机号验证(中国)^1[3-9]\d{9}$验证中国大陆手机号(11 位,第二位为 3-9)。 `^(13[0-9]14[5-9]URL 验证^(https?:\/\/)?([\w.-]+)\.([a-z]{2,})(:\d+)?(\/.*)?$支持 HTTP/HTTPS 协议、域名、端口和路径。 ^https?:\/\/(www\.)?[\w-]+\.[a-z]{2,}(\/.*)?$更简洁的 URL 验证(强制包含 www.)。密码强度验证^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$必须包含大小写字母、数字、特殊字符,长度 ≥8。 ^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,}$简化版(至少字母和数字,长度 ≥8)。提取 HTML 标签内容<(\w+)>(.*?)<\/\1>匹配简单标签内容(如 Hello)。 <([a-z]+)([^<]+)*(?:>(.*)<\/\1>)?更通用的标签匹配(支持属性和嵌套内容)。提取 URL 参数[?&]([^=#]+)=([^&#]*)提取查询字符串中的键值对(如 name=Alice&age=30)。 (?<=[?&])([^=&]+)=([^&]*)使用正向后顾匹配参数键值对。隐藏手机号中间四位(\d{3})\d{4}(\d{4})将手机号中间四位替换为星号(如 138****8000)。 (\d{3})\d{3}\d{4}另一种替换方式(如 138-***-8000)。千分位分隔符(?]+>删除所有 HTML 标签(如 Hello → Hello)。 <\/?[a-z][\w-]*[^>]*>更全面的标签匹配(支持属性和自闭合标签)。中文标点转英文标点[,。!?;:“”‘’()《》]替换常见中文标点为英文标点(如 ,→ ,)。 [^\x00-\x7F]匹配所有非 ASCII 字符(包括中文标点)。提取所有数字\d+匹配字符串中的连续数字(如 abc123def456 → ["123", "456"])。 \b\d+\b匹配独立数字(避免匹配日期中的数字如 2023-10-05 中的 2023)。验证身份证号(18位)^\d{15}(\d{2}[0-9xX])?$验证 15 位或 18 位身份证号(最后一位可为 X/x)。 `^[1-9]\d{5}(?:1920)\d{2}(?:0[1-9]2.对象操作2.1.对象的创建2.1.1. 对象字面量(Literal)最简洁的创建方式,直接用 {} 定义键值对:const obj = { name: 'dengke', age: 18, sayHi: () => console.log('Hello!'), };2.1.2. Object 构造函数通过 new Object() 创建对象:const obj = new Object(); obj.name = '孙悟空'; // 动态添加属性2.1.3. Object.create()指定原型链创建对象:const prototypeObj = { greet: () => 'Hello' }; const obj = Object.create(prototypeObj); // obj 的原型是 prototypeObj console.log(obj.greet()); // "Hello"2.1.4. 展开运算符(Spread)浅拷贝对象或合并对象:const obj1 = { a: 1 }; const obj2 = { b: 2 }; const merged = { ...obj1, ...obj2 }; // { a:1, b:2 }2.1.5.类实例化class Person { constructor(name, age){ this.name = name; this.age = age; } } const zs = new Person("zangsan",18); // Person {name:"zangsan".age:18}2.2.对象属性操作2.2.1. 增删改查添加/修改属性:obj.newProp = 'value'; // 点语法 obj['dynamicKey'] = 100; // 方括号语法(适合动态键名)删除属性:delete obj.newProp; // 返回布尔值,成功删除返回 true访问属性:console.log(obj.name); // 点语法 console.log(obj['age']); // 方括号语法2.2.2. 特殊键名的访问数字或特殊符号键名必须用方括号语法:const obj = { '1-key': 'value', '-abc': 100 }; console.log(obj['1-key']); // "value"2.3.对象遍历2.3.1. for...in 循环遍历对象自身和继承的可枚举属性:for (const key in obj) { if (obj.hasOwnProperty(key)) { // 过滤原型链属性 console.log(key, obj[key]); } }2.3.2. Object.keys() / Object.values() / Object.entries()Object.keys():返回对象自身可枚举属性的键数组:const keys = Object.keys(obj); // ["name", "age"]Object.values():返回属性值的数组:const values = Object.values(obj); // ["dengke", 18]Object.entries():返回键值对数组:const entries = Object.entries(obj); // [["name", "dengke"], ["age", 18]]2.3.3. Reflect.ownKeys()返回对象自身所有属性(包括不可枚举和符号键):const allKeys = Reflect.ownKeys(obj); // 包含所有属性2.4.对象属性描述符2.4.1. Object.defineProperty()定义或修改单个属性的描述符:const obj = {}; Object.defineProperty(obj, 'name', { value: 'dengke', // 属性值 writable: false, // 是否可修改(默认 false) enumerable: true, // 是否可枚举(默认 false) configurable: false // 是否可删除或修改描述符(默认 false) });2.4.2. Object.defineProperties()批量定义多个属性:Object.defineProperties(obj, { age: { value: 18, writable: true }, gender: { value: 'male', configurable: false } });2.4.3. 属性类型数据属性:直接存储值(如 name)。访问器属性:通过get和set方法控制访问:Object.defineProperty(obj, 'fullName', { get() { return `${this.firstName} ${this.lastName}`; }, set(val) { [this.firstName, this.lastName] = val.split(' '); } });2.5.对象冻结与密封2.5.1. Object.freeze()冻结对象,使其不可修改、不可扩展、不可配置:const obj = { a: 1 }; Object.freeze(obj); obj.a = 2; // 无效,对象被冻结2.5.2. Object.seal()密封对象,禁止添加新属性,但允许修改现有属性值:Object.seal(obj); obj.b = 3; // 无效,无法添加新属性 obj.a = 2; // 允许修改现有属性2.5.3. Object.preventExtensions()仅阻止添加新属性,其他操作仍允许:Object.preventExtensions(obj); obj.b = 4; // 无效2.5.4. 检查对象状态Object.isExtensible(obj); // 是否可扩展 Object.getOwnPropertyDescriptor(obj, 'a'); // 获取属性描述符2.6.对象合并与扩展2.6.1. Object.assign()合并对象,浅拷贝源对象到目标对象:const target = { a: 1 }; const source = { b: 2, a: 3 }; const result = Object.assign(target, source); console.log(result); // { a:3, b:2 }(目标对象被修改)2.6.2. 展开运算符(Spread)与 Object.assign() 类似,但语法更简洁:const merged = { ...target, ...source };2.7.Reflect API(ES6+)2.7.1. 常用方法Reflect.get() / Reflect.set():Reflect.get(obj, 'name'); // 等价于 obj.name Reflect.set(obj, 'age', 20); // 等价于 obj.age = 20Reflect.deleteProperty():Reflect.deleteProperty(obj, 'name'); // 等价于 delete obj.nameReflect.construct():const Person = function(name) { this.name = name; }; const instance = Reflect.construct(Person, ['dengke']);Reflect.has():Reflect.has(obj, 'name'); // 等价于 'name' in obj2.8.对象拷贝2.8.1.浅拷贝浅拷贝是指只拷贝对象的第一层属性,而嵌套对象的引用仍然指向原始对象。如果原始对象中的嵌套对象被修改,浅拷贝后的对象也会受到影响。Object.assign()const obj1 = { a: 1, b: { c: 2 } }; const obj2 = Object.assign({}, obj1); console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 3 (浅拷贝的嵌套对象引用被修改)展开运算符 (...)const obj1 = { a: 1, b: { c: 2 } }; const obj2 = { ...obj1 }; console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 3 (同样受影响)2.8.2.深拷贝JSON.parse() 和 JSON.stringify()const obj1 = { a: 1, b: { c: 2 } }; const obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2); // { a: 1, b: { c: 2 } } obj1.b.c = 3; console.log(obj2.b.c); // 2 (深拷贝后的对象不受影响)局限性:无法处理函数、undefined、Date、Map、Set 等特殊对象。无法处理循环引用(会导致栈溢出)。递归实现深拷贝function deepClone(obj, hash = new WeakMap()) { if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const result = Array.isArray(obj) ? [] : {}; hash.set(obj, result); for (const key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key], hash); } } return result; } const obj1 = { a: 1, b: { c: 2 }, d: [3, 4] }; const obj2 = deepClone(obj1); obj1.b.c = 3; console.log(obj2.b.c); // 2 (完全独立)优点:可以处理复杂对象(如 Date、Map、Set 等)。支持循环引用。使用库(如 Lodash 的 _.cloneDeep())const _ = require('lodash'); const obj1 = { a: 1, b: { c: 2 } }; const obj2 = _.cloneDeep(obj1); obj1.b.c = 3; console.log(obj2.b.c); // 2 (完全独立)2.9.常见陷阱与注意事项浅拷贝问题:Object.assign()和展开运算符仅复制对象的引用,修改嵌套对象会同步到源对象:const obj1 = { a: { b: 1 } }; const obj2 = { ...obj1 }; obj2.a.b = 2; // obj1.a.b 同样变为 2delete 操作符的限制:无法删除不可配置(configurable: false)的属性。for...in 的陷阱:会遍历原型链属性,需结合hasOwnProperty()过滤:for (const key in obj) { if (obj.hasOwnProperty(key)) { // 处理自身属性 } }Object.is() 的特殊比较:与 === 不同,Object.is(-0, 0) 返回 false,而 NaN === NaN 返回 true。3.数组操作3.1.数组的创建3.1.1. 字面量方式直接用 [] 定义数组:const arr = [1, 'apple', true];3.1.2. Array 构造函数通过 new Array() 创建:const arr1 = new Array(3); // 创建长度为3的空数组 [empty × 3] const arr2 = Array.of(1, 2, 3); // 推荐,避免构造函数的陷阱3.1.3. 填充数组const arr = Array(3).fill(0); // [0, 0, 0]3.2. 添加元素push()作用:向数组末尾添加一个或多个元素,并返回数组的新长度。示例:const arr = [1, 2, 3]; arr.push(4); // arr => [1, 2, 3, 4]unshift()作用:向数组开头添加一个或多个元素,并返回数组的新长度。示例:const arr = [1, 2, 3]; arr.unshift(0); // arr => [0, 1, 2, 3]splice()作用:向数组指定位置插入元素。语法:arr.splice(index, 0, element1, element2, ...)。示例:const arr = [1, 2, 3]; arr.splice(1, 0, 'a', 'b'); // arr => [1, 'a', 'b', 2, 3]3.3. 删除元素pop()作用:删除数组末尾的元素,并返回被删除的元素。示例:const arr = [1, 2, 3]; arr.pop(); // arr => [1, 2], 返回 3shift()作用:删除数组开头的元素,并返回被删除的元素。示例:const arr = [1, 2, 3]; arr.shift(); // arr => [2, 3], 返回 1splice()作用:删除数组指定位置的元素。语法:arr.splice(index, deleteCount)。示例:const arr = [1, 2, 3, 4, 5]; arr.splice(2, 1); // arr => [1, 2, 4, 5], 返回 [3]3.4. 查找元素indexOf()作用:查找元素在数组中的位置,返回第一个匹配的索引,未找到返回 -1。示例:const arr = [1, 2, 3, 2]; arr.indexOf(2); // 返回 1lastIndexOf()作用:从数组末尾开始查找元素,返回最后一个匹配的索引,未找到返回 -1。示例:const arr = [1, 2, 3, 2]; arr.lastIndexOf(2); // 返回 3find()作用:查找数组中第一个满足条件的元素,返回该元素。示例:const arr = [1, 2, 3, 4]; arr.find(item => item > 2); // 返回 3findIndex()作用:查找数组中第一个满足条件的元素的索引,未找到返回 -1。示例:const arr = [1, 2, 3, 4]; arr.findIndex(item => item > 2); // 返回 2findLast() / findLastIndex()作用:查找最后一个符合条件的元素:示例:const arr = [1, 2, 3, 2]; arr.findLastIndex(x => x === 2); // 3 const arr = [1, 2, 3, 2]; arr.findLast(x => x > 2); //33.5.修改元素直接赋值作用:直接修改数组中指定索引的元素。示例:const arr = [1, 2, 3]; arr[1] = 'a'; // arr => [1, 'a', 3]splice()作用:删除并插入新元素,实现替换功能。语法:arr.splice(index, deleteCount, element1, element2, ...)。示例:const arr = [1, 2, 3, 4, 5]; arr.splice(2, 1, 'a'); // arr => [1, 2, 'a', 4, 5]copyWithin作用:将数组的一部分复制到同一数组中的另一个位置,覆盖现有值。语法:array.copyWithin(target, start, end)示例:const array1 = ["a", "b", "c", "d", "e"]; console.log(array1.copyWithin(0, 3, 4)); // ["d", "b", "c", "d", "e"] console.log(array1.copyWithin(1, 3)); // ["d", "d", "e", "d", "e"]3.6. 遍历与转换map()作用:对数组中的每个元素执行函数,并返回一个新数组。示例:const arr = [1, 2, 3]; const newArr = arr.map(item => item * 2); // newArr => [2, 4, 6]filter()作用:过滤数组中的元素,返回满足条件的新数组。示例:const arr = [1, 2, 3, 4]; const newArr = arr.filter(item => item % 2 === 0); // newArr => [2, 4]forEach()作用:遍历数组中的每个元素,执行指定函数。示例:const arr = [1, 2, 3]; arr.forEach(item => console.log(item)); // 输出 1, 2, 3entries作用:返回一个包含数组中每个索引的键值对的迭代器。语法:array.entries()示例:const arr = ['a', 'b', 'c']; for (const [index, value] of arr.entries()) { console.log(index, value); } // 0 'a' // 1 'b' // 2 'c'reduce()作用:对数组中的元素进行累积操作,返回累积结果。语法:arr.reduce(callback(accumulator, currentValue), initialValue)。示例:const arr = [1, 2, 3, 4]; const sum = arr.reduce((acc, curr) => acc + curr, 0); // sum => 10flat作用:创建一个新的数组,并根据指定深度递归地将所有子数组元素拼接到新的数组中。语法:arr.flat([depth])示例:const arr1 = [0, 1, 2, [3, 4]]; console.log(arr1.flat()); // [0, 1, 2, 3, 4] const arr2 = [0, 1, [2, [3, [4, 5]]]]; console.log(arr2.flat(2)); // [0, 1, 2, 3, Array [4, 5]] console.log(arr2.flat(Infinity)); // [0, 1, 2, 3, 4, 5]flatMap()作用:结合了 map 和 flat 的功能,先对数组中的每个元素执行映射函数,然后将结果数组拍平一层。语法:arr.flatMap(callback(currentValue[, index[, array]])[, thisArg])示例:const nested = [[1], [2], [3]]; const flat = nested.flatMap(arr => arr); // [1,2,3] const arr = [1, 2, 3]; const result = arr.flatMap(x => [x, x * 2]); console.log(result); // [1, 2, 2, 4, 3, 6]3.6. 排序sort()作用:对数组进行排序,默认按字符串顺序排序。示例:const arr = [3, 1, 4, 2]; arr.sort(); // arr => [1, 2, 3, 4] (注意:默认按字符串排序)按数值排序:const arr = [3, 1, 4, 2]; arr.sort((a, b) => a - b); // arr => [1, 2, 3, 4]3.7. 合并与分割concat()作用:合并两个或多个数组,返回新数组。示例:const arr1 = [1, 2]; const arr2 = [3, 4]; const newArr = arr1.concat(arr2); // newArr => [1, 2, 3, 4]slice()作用:提取数组的一部分,返回新数组,不修改原数组。语法:arr.slice(start, end)(end 不包含)。示例:const arr = [1, 2, 3, 4]; const newArr = arr.slice(1, 3); // newArr => [2, 3]split()(字符串转数组)作用:将字符串分割为数组。示例:const str = 'a,b,c'; const arr = str.split(','); // arr => ['a', 'b', 'c']join()(数组转字符串)作用:将数组元素连接为字符串。示例:const arr = ['a', 'b', 'c']; const str = arr.join('-'); // str => 'a-b-c'3.8. 判断数组isArray()作用:判断一个对象是否为数组。示例:Array.isArray([1, 2, 3]); // true Array.isArray({}); // false3.9. 其他常用方法includes()作用:判断数组是否包含某个值,返回布尔值。示例:const arr = [1, 2, 3]; arr.includes(2); // truereverse()作用:反转数组。示例:const arr = [1, 2, 3]; arr.reverse(); // arr => [3, 2, 1]every()作用:判断数组中所有元素是否满足条件。示例:const arr = [2, 4, 6]; arr.every(item => item % 2 === 0); // truesome()作用:判断数组中是否存在至少一个满足条件的元素。示例:const arr = [1, 2, 3]; arr.some(item => item % 2 === 0); // true解构赋值const [first, second, ...rest] = [1,2,3,4]; console.log(first); // 1 console.log(rest); // [3,4]3.10.数组拷贝3.10.1. 浅拷贝slice()作用:创建一个新数组,包含原数组的元素(从开始索引到结束索引,但不包括结束索引)。语法:arr.slice([start], [end])示例:const arr = [1, 2, 3, 4]; const shallowCopy = arr.slice(); console.log(shallowCopy); // [1, 2, 3, 4]局限性:只拷贝第一层,嵌套对象的引用仍然共享。展开运算符 (...)作用:将数组展开为新数组。语法:const newArr = [...arr]示例:const arr = [1, 2, 3, 4]; const shallowCopy = [...arr]; console.log(shallowCopy); // [1, 2, 3, 4]局限性:同样只拷贝第一层。concat()作用:合并数组并返回新数组。语法:arr.concat()示例:const arr = [1, 2, 3, 4]; const shallowCopy = arr.concat(); console.log(shallowCopy); // [1, 2, 3, 4]局限性:只拷贝第一层。3.10.2. 深拷贝JSON.parse(JSON.stringify())作用:将数组转换为 JSON 字符串,再解析为新数组。语法:JSON.parse(JSON.stringify(arr))示例:const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = JSON.parse(JSON.stringify(arr)); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]]局限性:无法处理函数、undefined、Date、Map、Set 等特殊对象。无法处理循环引用。递归实现深拷贝作用:手动递归拷贝数组及其嵌套元素。实现:function deepClone(obj, hash = new WeakMap()) { if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const result = Array.isArray(obj) ? [] : {}; hash.set(obj, result); for (const key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key], hash); } } return result; } const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = deepClone(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]]优点:支持复杂对象和循环引用。缺点:实现复杂,性能较差。Lodash 的 _.cloneDeep()作用:使用 Lodash 库实现深拷贝。语法:_.cloneDeep(arr)示例:const _ = require('lodash'); const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = _.cloneDeep(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]]优点:功能强大,支持复杂对象和循环引用,性能较好。缺点:需要引入外部库。structuredClone()作用:使用现代浏览器的 structuredClone API。语法:structuredClone(arr)示例:const arr = [1, 2, { a: 3 }, [4, 5]]; const deepCopy = structuredClone(arr); console.log(deepCopy); // [1, 2, { a: 3 }, [4, 5]]优点:简单易用,支持多种数据类型,性能较好。缺点:不支持函数、Symbol 等某些特殊类型,浏览器兼容性有限。3.11.数组去重使用 Set:const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // [1, 2, 3, 4, 5]使用 filter 和 indexOf:const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.filter((item, index, self) => self.indexOf(item) === index); console.log(uniqueArr); // [1, 2, 3, 4, 5]使用 reduce:const arr = [1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.reduce((acc, item) => { if (!acc.includes(item)) { acc.push(item); } return acc; }, []); console.log(uniqueArr); // [1, 2, 3, 4, 5]3.12性能优化注意事项push 和 pop:O(1) 时间复杂度,效率高。unshift 和 shift:O(n) 时间复杂度,效率较低,尽量避免在大数据量时使用。splice:性能取决于删除/插入的位置和数量,尽量避免频繁使用。map 和 filter:遍历整个数组,复杂度为 O(n),适合中小规模数据。修改方法:push, pop, shift, unshift, splice, reverse, sort 会改变原数组。安全方法:map, filter, slice, concat 返回新数组。sort() 的默认行为:默认按字符串排序,需传入比较函数进行数值或自定义排序。slice() 和展开运算符 ([...arr]) 仅拷贝一层,嵌套对象仍为引用。4.高阶函数4.1.定义高阶函数指:接收函数作为参数(如 map、filter)。// 示例:回调函数 function repeat(n, callback) { for (let i = 0; i < n; i++) { callback(i); } } repeat(3, (index) => console.log(`Iteration ${index}`)); // 输出:Iteration 0, Iteration 1, Iteration 2返回函数作为结果(如柯里化、闭包)。// 示例:闭包 function createCounter() { let count = 0; return function() { return count++; }; } const counter = createCounter(); console.log(counter()); // 0 console.log(counter()); // 1或两者兼具。4.2.高阶函数用法4.2.1 柯里化将多参数函数转换为单参数函数链:function curryAdd(a) { return function(b) { return a + b; }; } const add5 = curryAdd(5); console.log(add5(3)); // 84.2.2函数组合组合多个函数为一个函数:function compose(f, g) { return function(x) { return f(g(x)); }; } const uppercase = str => str.toUpperCase(); const reverse = str => str.split('').reverse().join(''); const reverseUpper = compose(uppercase, reverse); console.log(reverseUpper("hello")); // "OLLEH"4.2.3.装饰器模式动态增强函数功能:function logger(fn) { return function(...args) { console.log("Calling function with", args); const result = fn.apply(this, args); console.log("Result:", result); return result; }; } const add = logger((a, b) => a + b); add(2, 3); // 输出日志并返回54.3.闭包闭包(Closure) 是一个函数与其词法作用域(Lexical Environment) 的组合。它允许函数访问并操作其外部函数的变量,即使外部函数已经执行完毕。4.3.1.工作原理词法作用域与执行上下文词法作用域:函数的作用域由其定义的位置决定。例如:function outer() { const outerVar = '外层变量'; function inner() { console.log(outerVar); // 引用外层变量 } return inner; } const closure = outer(); closure(); // 输出:外层变量inner 函数在定义时“记住”了 outer 的作用域,即使 outer 已执行完毕,inner 仍能访问 outerVar。词法环境(Lexical Environment)词法环境由两部分组成:环境记录(Environment Record):存储变量、函数声明等。外层环境引用(Outer Environment Reference):指向父级作用域。闭包的持久化:当外部函数执行完毕后,如果内部函数被外部引用,其词法环境不会被垃圾回收机制释放,从而形成闭包。垃圾回收机制JavaScript 的垃圾回收机制会回收不再被引用的变量和对象。闭包的内存问题:如果闭包引用了大量外部变量且长期存在,可能导致内存泄漏。4.3.2.应用场景数据封装与私有变量模拟私有变量:function Counter() { let count = 0; // 私有变量 return { increment: () => count++, get: () => count }; } const counter = Counter(); console.log(counter.get()); // 0 counter.increment(); console.log(counter.get()); // 1count 是外部函数 Counter 的局部变量,通过闭包被内部方法访问,外部无法直接修改。保存状态(持续化变量)计数器示例:function createCounter() { let count = 0; return () => count++; } const counter = createCounter(); console.log(counter()); // 0 console.log(counter()); // 1count 的值在每次调用时被保留,形成“持续状态”。回调函数与异步编程异步操作中保存上下文:function asyncTask(data) { setTimeout(() => { console.log(`处理数据: ${data}`); }, 1000); } asyncTask("Hello"); // 1秒后输出 "处理数据: Hello"setTimeout 的回调函数通过闭包访问了外部函数 asyncTask 的参数 data。5.解构操作5.1.数组结构基本用法const arr = [1, 2, 3]; const [a, b, c] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3跳过元素//你可以通过在解构模式中留空来跳过数组中的某些元素。 const arr = [1, 2, 3, 4, 5]; const [a, , b, , c] = arr; console.log(a); // 1 console.log(b); // 3 console.log(c); // 5默认值//如果数组中的某些元素不存在,你可以为变量提供默认值。 const arr = [1, 2]; const [a, b, c = 3] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3嵌套解构const arr = [1, [2, 3], 4]; const [a, [b, c], d] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(d); // 4剩余参数const [head, ...tail] = [1, 2, 3, 4]; console.log(head); // 1 console.log(tail); // [2, 3, 4]5.2.对象解构基本用法const obj = { a: 1, b: 2, c: 3 }; const { a, b, c } = obj; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3重命名变量你可以为解构的属性指定不同的变量名。const obj = { a: 1, b: 2 }; const { a: x, b: y } = obj; console.log(x); // 1 console.log(y); // 2默认值如果对象中没有某个属性,你可以为变量提供默认值。const obj = { a: 1 }; const { a, b = 2 } = obj; console.log(a); // 1 console.log(b); // 2嵌套解构对象解构支持嵌套结构。const obj = { a: 1, b: { c: 2, d: 3 }, e: 4 }; const { a, b: { c, d }, e } = obj; console.log(a); // 1 console.log(c); // 2 console.log(d); // 3 console.log(e); // 4剩余参数const { id, ...rest } = { id: 1, name: 'Bob', age: 25 }; console.log(rest); // { name: 'Bob', age: 25 }5.3.函数参数解构// 对象解构 function printUser({ name, age }) { console.log(`Name: ${name}, Age: ${age}`); } printUser({ name: 'Alice', age: 30 }); // Name: Alice, Age: 30 // 数组解构 function sum([a, b]) { return a + b; } console.log(sum([1, 2])); // 35.4.复杂嵌套结构const data = { user: { name: "Bob", address: { city: "New York" } }, hobbies: ["reading", "coding"] }; // 解构嵌套对象 const { user: { name, address: { city } }, hobbies: [firstHobby, ...otherHobbies] } = data; console.log(name, city); // "Bob" "New York" console.log(firstHobby, otherHobbies); // "reading" ["coding"]5.5.应用场景交换变量值通过解构实现变量交换:let x = 1, y = 2; [x, y] = [y, x]; // x=2, y=1字符串解构将字符串视为字符数组进行解构:const [a, b, c] = 'cat'; // a='c', b='a', c='t'计算属性名用表达式作为属性名:const key = 'age'; const obj = { age: 25 }; const { [key]: userAge } = obj; // userAge=25从函数返回多个值function getCoordinates() { return { x: 10, y: 20 }; } const { x, y } = getCoordinates(); console.log(x, y); // 10 20忽略不需要的值const [onlyFirst, , third] = [1, 2, 3]; console.log(onlyFirst, third); // 1 3解构与模块导入// mathUtils.js export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; // main.js import { add, subtract } from "./mathUtils.js"; console.log(add(5, 3)); // 86.JSON操作6.1.JSON.stringify()将对象或数组转为字符串,支持过滤、转换和格式化。语法:JSON.stringify(value[, replacer[, space]])value: 要序列化的对象。replacer(可选):函数或数组,用于过滤或转换属性。space(可选):格式化缩进(数字或字符串)。示例const obj = { name: "Alice", age: 25, date: new Date() }; // 基础序列化 console.log(JSON.stringify(obj)); // '{"name":"Alice","age":25,"date":"2023-10-01T00:00:00.000Z"}' // 过滤属性(仅保留 name 和 age) console.log(JSON.stringify(obj, ["name", "age"])); // '{"name":"Alice","age":25}' // 使用 replacer 函数 console.log(JSON.stringify(obj, (key, value) => { if (key === "date") return value.toISOString(); // 格式化日期 return value; })); //用于指定缩进空格数,使输出的 JSON 字符串更易读。 const obj = { name: 'Alice', age: 30 }; const jsonString = JSON.stringify(obj, null, 2); console.log(jsonString); // { // "name": "Alice", // "age": 30 // }循环引用问题:默认无法处理循环引用,会导致错误。可以通过 replacer 函数来处理。const obj = { a: 1 }; obj.b = obj; try { JSON.stringify(obj); // 抛出错误 } catch (e) { console.error('Error:', e.message); } // 使用 replacer 处理循环引用 function replacer(key, value) { if (value === obj) return '[Circular]'; return value; } console.log(JSON.stringify(obj, replacer)); // '{"a":1,"b":"[Circular]"}'JSON.stringify() 会忽略函数、undefined和 Symbol 键:const obj = { name: 'Alice', greet: function() { console.log('Hello!'); }, id: Symbol('123') }; console.log(JSON.stringify(obj)); // '{"name":"Alice"}'6.2.JSON.parse()将 JSON 字符串转换为 JavaScript 对象或数组。语法:JSON.parse(text[, reviver])text:要解析的 JSON 字符串。reviver(可选):函数,用于在解析后转换结果(如类型转换或数据校验)。示例const jsonString = '{"name":"Alice","age":30}'; const obj = JSON.parse(jsonString); console.log(obj); // { name: 'Alice', age: 30 } //reviver const jsonString = '{"name":"Alice","age":30,"email":"alice@example.com"}'; const obj = JSON.parse(jsonString, (key, value) => { if (key === 'email') return value.toUpperCase(); return value; }); console.log(obj); // { name: 'Alice', age: 30, email: 'ALICE@EXAMPLE.COM' } //如果 JSON 字符串格式不正确,JSON.parse() 会抛出错误。 const invalidJson = '{"name": "Alice",}'; // 额外的逗号 try { JSON.parse(invalidJson); } catch (e) { console.error('Error:', e.message); // Error: Unexpected token } at position 15 }7.集合7.1.Map用于键值对存储,键可以是任何数据类型(包括对象、函数等)。保持插入顺序。7.1.1.方法方法功能描述new Map()创建一个空的 Map。.set(key, value)设置键值对,若键存在则更新值,返回 Map 本身。.get(key)获取指定键的值,若不存在返回 undefined。.has(key)检查是否存在指定键。.delete(key)删除指定键的键值对,返回是否删除成功。.clear()清空所有键值对。.keys()返回一个包含所有键的迭代器。.values()返回一个包含所有值的迭代器。.entries()返回一个包含 [key, value] 数组的迭代器。.forEach(callback)遍历所有键值对,回调参数为 (value, key, map)。示例const map = new Map([ ["name", "Alice"], [42, "The Answer"] ]); // 添加/删除元素 map.set("age", 25); // Map(3) { "name" → "Alice", 42 → "The Answer", "age" → 25 } map.delete("name"); // true → 移除键 "name" // 查询与遍历 map.get(42); // "The Answer" map.has("age"); // true map.size; // 2 // 遍历 map.forEach((value, key) => console.log(`${key}: ${value}`)); //使用对象 const user = { id: 1 }; const userMap = new Map(); userMap.set(user, "Alice"); // 键是对象 console.log(userMap.get(user)); // "Alice" //动态的键值对 const cache = new Map(); cache.set("key1", "value1"); cache.set(123, { data: "test" }); // 对象转 Map const obj = { a: 1, b: 2 }; const mapFromObj = new Map(Object.entries(obj)); // Map { "a" → 1, "b" → 2 } // Map 转对象 const objFromMap = Object.fromEntries(mapFromObj); // { a: 1, b: 2 } //Map转数组 const arr = Array.from(map);7.1.2.和Object比较特性Map对象(Object)键的类型任意类型(包括对象、函数等)仅字符串或符号(Symbol)遍历顺序保持插入顺序无保证(ES5 及之前)大小查询map.size需手动统计或 Object.keys().length性能更适合频繁增删改的场景适合简单的键值存储7.2.Set集合(Set)是一种数据结构,用于存储唯一的值。集合中的元素是唯一的,这意味着集合中不能有重复的值。集合提供了多种方法来添加、删除和检查元素。7.2.1.基本方法方法功能描述new Set()创建一个空的 Set。.add(value)向集合中添加一个元素,若已存在则不操作,返回 Set 本身。.delete(value)从集合中删除指定元素,返回是否删除成功(true/false)。.has(value)检查集合中是否存在指定元素,返回布尔值。.clear()清空集合中的所有元素。.size返回集合中元素的数量。.forEach(callback)遍历集合中的每个元素,执行回调函数。也可以用for...of.values()返回一个包含集合中所有值的迭代器。// 通过数组初始化 const fruits = new Set(["apple", "banana", "cherry"]); // 逐步添加元素 const numbers = new Set(); numbers.add(1).add(2).add(3); // 链式调用 // 通过变量添加元素 const name = "Alice"; const users = new Set(); users.add(name); // 添加字符串 users.add({ id: 1 }); // 添加对象 //遍历 const mySet = new Set([1, 2, 3]); for (const value of mySet) { console.log(value); } // 1 // 2 // 3 const mySet = new Set([1, 2, 3]); mySet.forEach(value => { console.log(value); }); // 1 // 2 // 3 //集合转数组 const mySet = new Set([1, 2, 3]); const arr = Array.from(mySet); // 或 [...mySet] console.log(arr); // [1, 2, 3]NaN:虽然 NaN !== NaN,但 Set 中只会存储一个 NaN。null/undefined:会被视为唯一值,但多次添加不会重复。7.2.2.高级方法union():合并两个 Set,去重后返回新 Set。intersection():返回两个 Set 的交集。difference():返回在第一个 Set 中但不在第二个中的元素。symmetricDifference():返回两个 Set 的非交集元素。const setA = new Set([1, 2, 3]); const setB = new Set([3, 4, 5]); // 合并 const unionSet = setA.union(setB); // {1, 2, 3, 4, 5} // 交集 const intersectionSet = setA.intersection(setB); // {3} // 差集 const differenceSet = setA.difference(setB); // {1, 2} // 对称差集 const symDiffSet = setA.symmetricDifference(setB); // {1, 2, 4, 5}7.2.3.应用去重与统计频率const arr = [1, 2, 2, 3, 3, 3]; const frequency = [...new Set(arr)].reduce((acc, num) => { acc[num] = arr.filter(x => x === num).length; return acc; }, {}); // {1:1, 2:2, 3:3}8.日期处理8.1. 创建日期对象当前日期和时间:const now = new Date(); console.log(now); // 当前日期和时间指定日期和时间:const specificDate = new Date(2023, 9, 15, 12, 30, 0); // 年, 月(0-11), 日, 时, 分, 秒 console.log(specificDate); // 2023-10-15T12:30:00日期字符串:const dateString = new Date('2023-10-15T12:30:00'); console.log(dateString); // 2023-10-15T12:30:008.2. 获取日期和时间获取年份:const year = new Date().getFullYear(); console.log(year); // 2023获取月份(0-11):const month = new Date().getMonth(); console.log(month); // 9 (十月)获取日期:const day = new Date().getDate(); console.log(day); // 15获取星期几(0-6,0 表示星期日):const dayOfWeek = new Date().getDay(); console.log(dayOfWeek); // 0-6获取小时:const hours = new Date().getHours(); console.log(hours); // 0-23获取分钟:const minutes = new Date().getMinutes(); console.log(minutes); // 0-59获取秒数:const seconds = new Date().getSeconds(); console.log(seconds); // 0-59获取毫秒:const milliseconds = new Date().getMilliseconds(); console.log(milliseconds); // 0-9993. 设置日期和时间设置年份:const date = new Date(); date.setFullYear(2024); console.log(date.getFullYear()); // 2024设置月份:const date = new Date(); date.setMonth(11); // 11 表示 12 月 console.log(date.getMonth()); // 11设置日期:const date = new Date(); date.setDate(20); console.log(date.getDate()); // 20设置小时:const date = new Date(); date.setHours(15); console.log(date.getHours()); // 15设置分钟:const date = new Date(); date.setMinutes(30); console.log(date.getMinutes()); // 30设置秒数:const date = new Date(); date.setSeconds(45); console.log(date.getSeconds()); // 45设置毫秒:const date = new Date(); date.setMilliseconds(500); console.log(date.getMilliseconds()); // 5008.4. 日期格式化使用 toLocaleDateString():const date = new Date(); console.log(date.toLocaleDateString()); // 2023/10/15 (格式取决于浏览器的本地设置)自定义格式化:function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } const date = new Date(); console.log(formatDate(date)); // 2023-10-15使用 Intl.DateTimeFormat(推荐)const date = new Date(); const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZone: 'Asia/Shanghai' // 指定时区 }; console.log(new Intl.DateTimeFormat('zh-CN', options).format(date)); // "2023/12/25 10:30:00"使用第三方库(如 date-fns)import { format } from 'date-fns'; import { zhCN } from 'date-fns/locale'; console.log(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: zhCN })); // "2023-12-25 10:30:00"8.5. 日期计算计算两个日期之间的天数差:function daysBetween(date1, date2) { const diffTime = Math.abs(date2 - date1); return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } const date1 = new Date('2023-10-01'); const date2 = new Date('2023-10-15'); console.log(daysBetween(date1, date2)); // 14添加天数到日期:function addDays(date, days) { const newDate = new Date(date); newDate.setDate(newDate.getDate() + days); return newDate; } const date = new Date('2023-10-15'); const newDate = addDays(date, 5); console.log(newDate); // 2023-10-20时间戳const now = new Date(); const timestamp = now.getTime(); // 获取当前时间戳(毫秒) console.log(timestamp); // 例如:1712023102000 // 通过Date.now()快速获取时间戳 console.log(Date.now()); // 等同于new Date().getTime()8.6. 时区处理获取 UTC 时间:const date = new Date(); console.log(date.toUTCString()); // Wed, 18 Oct 2023 04:30:00 GMT获取本地时间:const date = new Date(); console.log(date.toLocaleString()); // 2023/10/15 下午12:30:00 (格式取决于浏览器的本地设置)10.事件10.1.Event对象用户或浏览器触发的交互行为(如点击、键盘输入、页面加载等)。事件处理函数的参数 event 包含交互的详细信息:常用属性属性描述event.type事件类型(如 "click")。event.target触发事件的实际元素(原始目标)。event.currentTarget当前处理事件的元素(绑定监听器的元素)。event.preventDefault()阻止默认行为(如表单提交、链接跳转)。event.stopPropagation()阻止事件冒泡/捕获。event.clientX/Y鼠标事件的坐标(相对于视口)。示例代码:button.addEventListener("click", (event) => { console.log("目标元素:", event.target); // 实际点击的元素 console.log("当前元素:", event.currentTarget); // 绑定事件的元素 event.preventDefault(); // 阻止默认行为(如表单提交) event.stopPropagation(); // 阻止事件冒泡 });10.2.事件传播机制事件传播分为三个阶段:捕获阶段(Capture Phase):事件从 window 向下传递到目标元素。目标阶段(Target Phase):事件到达目标元素。冒泡阶段(Bubble Phase):事件从目标元素向上传递回 window。示例:点击嵌套元素 div > p 时的事件流顺序:window → document → html → body → div → p(捕获阶段) p → div → body → html → document → window(冒泡阶段)事件委托:利用事件冒泡机制,将事件监听器绑定到父元素,处理子元素的事件:<ul id="parent"> <li>Item 1</li> <li>Item 2</li> </ul>const parent = document.getElementById("parent"); parent.addEventListener("click", (event) => { if (event.target.tagName === "LI") { console.log("列表项被点击:", event.target.textContent); } });10.3.自定义事件// 创建自定义事件 const customEvent = new CustomEvent("myEvent", { detail: { message: "Hello!" }, }); // 触发事件 document.dispatchEvent(customEvent); // 监听自定义事件 document.addEventListener("myEvent", (event) => { console.log("自定义事件触发:", event.detail.message); });10.4.常用事件事件类别事件名称触发时机备注用户界面事件click鼠标点击元素时触发最常用事件之一 dblclick双击元素时触发注意防止双击选中文本 contextmenu右键点击元素时触发(默认弹出右键菜单)可用 event.preventDefault() 阻止默认行为 mousedown鼠标按下时触发常用于拖拽功能 mouseup鼠标释放时触发与 mousedown 配合使用焦点事件focus元素获得焦点时触发(如输入框点击、激活)不冒泡 blur元素失去焦点时触发不冒泡 focusin元素获得焦点时触发(支持冒泡)可用于事件委托 focusout元素失去焦点时触发(支持冒泡)同上鼠标事件mouseover鼠标进入元素或其子元素时触发会冒泡 mouseout鼠标离开元素或其子元素时触发会冒泡 mouseenter鼠标进入元素时触发(不检测子元素)不冒泡 mouseleave鼠标离开元素时触发(不检测子元素)不冒泡 mousemove鼠标在元素上移动时触发高频触发,需注意性能键盘事件keydown按下键盘按键时触发(字符键和功能键)可获取 event.key 或 event.keyCode keypress按下字符键时触发(已废弃,推荐用 keydown) keyup松开键盘按键时触发 表单事件submit表单提交时触发(如点击提交按钮)可阻止默认提交行为 change表单元素值改变且失去焦点时触发(如输入框、下拉框)常用于实时验证 input表单元素值改变时立即触发(无需失去焦点)实时性更强 reset表单重置时触发 窗口事件resize浏览器窗口大小改变时触发需节流处理高频触发 scroll页面或元素滚动时触发需优化性能 load页面或图片等资源完全加载完成时触发常用于 window 或 `` unload页面卸载时触发(如关闭标签页)不推荐使用,存在兼容性问题拖放事件dragstart拖拽操作开始时触发需设置元素为 draggable="true" dragover拖拽元素在目标元素上方移动时触发需调用 event.preventDefault() drop拖拽元素在目标元素上释放时触发 剪贴板事件copy复制操作时触发可修改剪贴板内容 cut剪切操作时触发 paste粘贴操作时触发 资源加载事件error资源加载失败时触发(如图片、脚本) 触摸事件touchstart手指触摸屏幕时触发移动端常用 touchmove手指在屏幕上滑动时触发需调用 event.preventDefault() 防止页面滚动 touchend手指离开屏幕时触发 11.BOM11.1.Window对象代表浏览器窗口(全局对象)常用属性location:访问当前窗口的 Location 对象。history:访问当前窗口的 History 对象。navigator:访问当前浏览器的 Navigator 对象。screen:访问当前屏幕的 Screen 对象。document:访问当前窗口的文档对象(DOM 根对象)。innerWidth/innerHeight:获取窗口内部宽度/高度(包含滚动条)。outerWidth/outerHeight:获取窗口外部宽度/高度(包含浏览器边框和工具栏)。常用方法方法名说明示例alert()显示警告对话框window.alert("提示信息");confirm()显示确认对话框(返回布尔值)if (window.confirm("确定提交?")) { ... }prompt()显示输入对话框(返回输入值或 null)let input = window.prompt("请输入");setTimeout()设置定时器,延迟执行代码setTimeout(() => { console.log("执行"); }, 1000);setInterval()设置周期性定时器setInterval(() => { console.log("每秒执行"); }, 1000);clearTimeout()/clearInterval()清除定时器clearTimeout(timerId);open()打开新窗口或标签页window.open("https://example.com");close()关闭当前或指定窗口window.close();resizeTo()调整窗口大小window.resizeTo(800, 600);moveTo()移动窗口到指定坐标window.moveTo(100, 100);scrollTo()/scrollBy()滚动页面到指定位置window.scrollTo(0, document.body.scrollHeight);11.2.Navigator对象浏览器对象属性描述navigator.appName获取浏览器的名称navigator.appVersion获取浏览器的平台和版本信息navigator.language获取当前浏览器的语言navigator.userAgent获取用户代理字符串navigator.cookieEnabled获取浏览器是否启用cookienavigator.onLine获取浏览器是否处于在线模式navigator.platform获取运行浏览器的操作系统平台方法名说明geolocation.getCurrentPosition()获取用户地理位置vibrate()触发设备振动(需权限)sendBeacon()异步发送小数据到服务器11.3.Location浏览器的地址栏信息属性名说明href完整 URL(如 https://example.com/path?query#hash)protocolURL 的协议(如 https:)host主机名 + 端口号(如 example.com:8080)hostname主机名(如 example.com)port端口号(如 8080)pathname路径部分(如 /path)search查询字符串(如 ?key=value)hash锚点部分(如 #section)origin协议、主机和端口的组合(如 https://example.com)searchParamsURL 查询参数的 URLSearchParams 对象(ES6+)常用方法方法名说明assign(url)加载新 URL(替换当前历史记录)replace(url)替换当前页面且不生成历史记录reload()重新加载当前页面11.4.History属性描述history.length返回历史浏览记录的当前长度方法说明back()返回上一页(等同于浏览器的后退按钮)forward()前进到下一页go(n)跳转到指定历史记录索引(0 为当前页,-1 为上一页)pushState(state, title, url)无刷新添加历史记录条目(SPA 常用)replaceState(state, title, url)替换当前历史记录条目(无刷新)11.5.screen属性名说明availWidth屏幕可用宽度(排除任务栏)availHeight屏幕可用高度(排除任务栏)width屏幕总宽度(含任务栏)height屏幕总高度(含任务栏)colorDepth屏幕颜色深度(位数)11.6.Document方法描述示例代码getElementById(id)根据元素的 ID 获取元素。const element = document.getElementById('myId');querySelector(selector)使用 CSS 选择器获取第一个匹配的元素。const element = document.querySelector('#myId');querySelectorAll(selector)使用 CSS 选择器获取所有匹配的元素,返回一个静态节点列表。const elements = document.querySelectorAll('.myClass');getElementsByClassName(name)根据类名获取元素,返回一个 HTML 集合。const elements = document.getElementsByClassName('myClass');getElementsByTagName(name)根据标签名获取元素,返回一个 HTML 集合。const elements = document.getElementsByTagName('div');createElement(tagName)创建一个新的 HTML 元素。const newElement = document.createElement('div');createTextNode(text)创建一个新的文本节点。const textNode = document.createTextNode('Hello, World!');appendChild(node)将一个节点添加到父节点的子节点列表的末尾。parentElement.appendChild(newElement);insertBefore(node, referenceNode)在参考节点之前插入一个节点。parentElement.insertBefore(newElement, referenceNode);removeChild(node)从父节点中移除一个子节点。parentElement.removeChild(childElement);replaceChild(newNode, oldNode)用新节点替换旧节点。parentElement.replaceChild(newNode, oldNode);addEventListener(type, listener)为元素添加事件监听器。element.addEventListener('click', function() { console.log('Clicked!'); });removeEventListener(type, listener)移除元素的事件监听器。element.removeEventListener('click', myFunction);getAttribute(name)获取元素的指定属性值。const value = element.getAttribute('href');setAttribute(name, value)设置元素的指定属性值。element.setAttribute('href', 'https://example.com');removeAttribute(name)移除元素的指定属性。element.removeAttribute('href');innerHTML获取或设置元素的 HTML 内容。element.innerHTML = 'New content';textContent获取或设置元素的文本内容(不解析 HTML)。element.textContent = 'New text';style获取或设置元素的样式。element.style.color = 'red';classList操作元素的类列表。element.classList.add('myClass');getComputedStyle(element)获取元素的计算样式。const style = window.getComputedStyle(element);输出流方法描述示例代码document.write()向文档写入 HTML 内容(慎用,仅在页面加载前使用)。document.write("Hello");document.writeln()写入 HTML 内容并换行。document.writeln("Line 1 Line 2");示例代码// 通过 ID 获取元素 const elementById = document.getElementById('myId'); // 通过类名获取元素 const elementsByClass = document.getElementsByClassName('myClass'); // 通过标签名获取元素 const elementsByTag = document.getElementsByTagName('div'); // 使用 CSS 选择器获取元素 const elementBySelector = document.querySelector('#myId'); const elementsBySelector = document.querySelectorAll('.myClass'); const href = element.getAttribute("href"); // 获取属性值 // 创建新元素 const newDiv = document.createElement('div'); newDiv.textContent = 'New content'; // 添加到文档 document.body.appendChild(newDiv); // 在指定位置插入元素 const referenceElement = document.getElementById('reference'); referenceElement.parentNode.insertBefore(newDiv, referenceElement); element.setAttribute("title", "点击查看详情"); // 设置属性 element.removeAttribute("data-old"); // 删除属性 element.checked = true; // 复选框选中状态 element.disabled = false; // 启用按钮 // 添加点击事件监听器 const button = document.getElementById('myButton'); button.addEventListener('click', function() { console.log('Button clicked!'); }); // 移除事件监听器 function handleClick() { console.log('Button clicked!'); } button.removeEventListener('click', handleClick); 【学习笔记】Javascript(一) Javascript基础1.HelloWorld1.1<script>标签<!DOCTYPE h... 最后修改:2026 年 01 月 22 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏 文章引用 反向引用 Loading... 暂未引用其他文章 暂未被其它文章引用 下一篇 上一篇 发表评论 取消回复 使用cookie技术保留您的个人信息以便您下次快速评论,继续评论表示您已同意该条款 评论 * 私密评论 名称 * 🎲 邮箱 * 地址 发表评论 提交中...