汇总 JavaScript 内置对象常用方法详解
JavaScript 提供了许多强大的内置对象,它们带有各种实用的方法,能够帮助我们更高效地编写代码。本文将介绍最常用的内置对象方法,并通过实例展示它们的使用场景。
目录
- Array 数组
- String 字符串
- Object 对象
- Date 日期
- Math 数学
- Promise 异步处理
Array 数组
1. map() - 映射数组
使用场景:当你需要对数组的每个元素进行相同的操作,并返回一个新数组时。
示例代码:
// 将数组中的每个数字翻倍
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((num) => num * 2);
console.log(doubled); // 输出: [2, 4, 6, 8, 10]// 从对象数组中提取特定属性
const users = [{ name: "张三", age: 25 },{ name: "李四", age: 30 },{ name: "王五", age: 22 },
];
const names = users.map((user) => user.name);
console.log(names); // 输出: ['张三', '李四', '王五']
图解:
注意事项:
- map() 不会修改原数组,而是返回一个新数组
- 对空数组调用 map() 会返回空数组
- 如果不需要返回值,考虑使用 forEach() 方法
2. filter() - 过滤数组
使用场景:当你需要从数组中筛选出符合条件的元素时。
示例代码:
// 筛选出大于10的数字
const numbers = [5, 12, 8, 20, 3];
const largeNumbers = numbers.filter((num) => num > 10);
console.log(largeNumbers); // 输出: [12, 20]// 筛选出年龄大于25的用户
const users = [{ name: "张三", age: 25 },{ name: "李四", age: 30 },{ name: "王五", age: 22 },
];
const adults = users.filter((user) => user.age > 25);
console.log(adults); // 输出: [{ name: '李四', age: 30 }]
图解:
注意事项:
- filter() 不会修改原数组
- 如果没有元素满足条件,返回空数组
- filter() 会跳过数组中的空位
3. reduce() - 累加器
使用场景:当你需要将数组中的所有元素归纳为单个值时。
示例代码:
// 计算数组元素总和
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue,0
);
console.log(sum); // 输出: 15// 统计数组中各元素出现次数
const fruits = ["苹果", "香蕉", "苹果", "橙子", "香蕉", "苹果"];
const countMap = fruits.reduce((acc, fruit) => {acc[fruit] = (acc[fruit] || 0) + 1;return acc;
}, {});
console.log(countMap); // 输出: { '苹果': 3, '香蕉': 2, '橙子': 1 }
注意事项:
- reduce() 需要一个回调函数和一个初始值(可选)
- 如果没有提供初始值,会使用数组的第一个元素作为初始值
- 在空数组上调用 reduce() 没有初始值会报错
4. forEach() - 遍历数组
使用场景:当你需要对数组中的每个元素执行操作,但不需要返回新数组时。
示例代码:
// 打印数组中的每个元素
const fruits = ["苹果", "香蕉", "橙子"];
fruits.forEach((fruit, index) => {console.log(`${index}: ${fruit}`);
});
// 输出:
// 0: 苹果
// 1: 香蕉
// 2: 橙子// 对象数组操作
const users = [{ name: "张三", age: 25 },{ name: "李四", age: 30 },
];
let totalAge = 0;
users.forEach((user) => {totalAge += user.age;
});
console.log(`平均年龄: ${totalAge / users.length}`); // 输出: 平均年龄: 27.5
注意事项:
- forEach() 不会返回值,总是返回 undefined
- 无法使用 break 或 continue 中断循环,如需中断应使用普通 for 循环
- 如果需要构建新数组,使用 map()、filter() 等方法更适合
5. find() 和 findIndex() - 查找元素
使用场景:当你需要在数组中查找符合条件的元素或其索引时。
示例代码:
// 查找第一个偶数
const numbers = [1, 3, 5, 8, 9, 10];
const firstEven = numbers.find((num) => num % 2 === 0);
console.log(firstEven); // 输出: 8// 查找符合条件元素的索引
const firstEvenIndex = numbers.findIndex((num) => num % 2 === 0);
console.log(firstEvenIndex); // 输出: 3// 在对象数组中查找
const users = [{ id: 1, name: "张三" },{ id: 2, name: "李四" },{ id: 3, name: "王五" },
];
const user = users.find((user) => user.id === 2);
console.log(user); // 输出: { id: 2, name: "李四" }
注意事项:
- find() 返回第一个满足条件的元素,findIndex() 返回其索引
- 如果没有找到匹配项,find() 返回 undefined,findIndex() 返回 -1
- ES6 新增方法,对于旧浏览器可能需要 polyfill
6. some() 和 every() - 条件检查
使用场景:当你需要检查数组是否满足某些条件时。
示例代码:
const numbers = [1, 2, 3, 4, 5];// some() 检查是否至少有一个元素满足条件
const hasEven = numbers.some((num) => num % 2 === 0);
console.log(hasEven); // 输出: true// every() 检查是否所有元素都满足条件
const allPositive = numbers.every((num) => num > 0);
console.log(allPositive); // 输出: trueconst allEven = numbers.every((num) => num % 2 === 0);
console.log(allEven); // 输出: false// 实际应用:表单验证
const formValues = [{ field: "username", value: "user123" },{ field: "email", value: "test@example.com" },{ field: "password", value: "" },
];
const isFormValid = formValues.every((field) => field.value.length > 0);
console.log(isFormValid); // 输出: false
注意事项:
- some() 在找到第一个满足条件的元素时就会返回 true 并停止遍历
- every() 在找到第一个不满足条件的元素时就会返回 false 并停止遍历
- 对空数组调用 every() 总是返回 true,对空数组调用 some() 总是返回 false
7. sort() - 排序数组
使用场景:当你需要对数组元素进行排序时。
示例代码:
// 字符串数组排序(默认按字母顺序)
const fruits = ["香蕉", "苹果", "橙子", "葡萄"];
fruits.sort();
console.log(fruits); // 输出: ["橙子", "苹果", "葡萄", "香蕉"]// 数字数组排序(需要比较函数)
const numbers = [40, 100, 1, 5, 25, 10];
// 升序排序
numbers.sort((a, b) => a - b);
console.log(numbers); // 输出: [1, 5, 10, 25, 40, 100]// 降序排序
numbers.sort((a, b) => b - a);
console.log(numbers); // 输出: [100, 40, 25, 10, 5, 1]// 对象数组排序
const users = [{ name: "张三", age: 30 },{ name: "李四", age: 24 },{ name: "王五", age: 28 },
];
// 按年龄排序
users.sort((a, b) => a.age - b.age);
console.log(users);
// 输出: [
// { name: "李四", age: 24 },
// { name: "王五", age: 28 },
// { name: "张三", age: 30 }
// ]
注意事项:
- sort() 会改变原数组
- 默认排序是按字符串 Unicode 码点排序
- 对数字排序需要提供比较函数,否则 [100, 2, 1] 会被排序为 [1, 100, 2]
- 对于复杂排序逻辑,可以组合多种条件
8. concat() - 合并数组
使用场景:当你需要将多个数组合并为一个新数组时。
示例代码:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];// 合并两个数组
const merged = arr1.concat(arr2);
console.log(merged); // 输出: [1, 2, 3, 4, 5, 6]// 合并多个数组
const mergedAll = arr1.concat(arr2, arr3);
console.log(mergedAll); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]// 合并值和数组
const mergedWithValues = arr1.concat(4, [5, 6], 7);
console.log(mergedWithValues); // 输出: [1, 2, 3, 4, 5, 6, 7]
注意事项:
- concat() 不会修改原数组,而是返回一个新数组
- 可以连接多个数组或值
- 如果传入的参数是数组,会将其元素添加到结果数组中
- ES6 中可以使用扩展运算符
[...arr1, ...arr2]
代替
9. slice() - 提取数组片段
使用场景:当你需要从数组中提取部分元素而不修改原数组时。
示例代码:
const numbers = [0, 1, 2, 3, 4, 5];// 从索引1到索引3(不包括4)
const sliced1 = numbers.slice(1, 4);
console.log(sliced1); // 输出: [1, 2, 3]// 从索引2到末尾
const sliced2 = numbers.slice(2);
console.log(sliced2); // 输出: [2, 3, 4, 5]// 提取最后两个元素
const sliced3 = numbers.slice(-2);
console.log(sliced3); // 输出: [4, 5]// 复制整个数组
const copy = numbers.slice();
console.log(copy); // 输出: [0, 1, 2, 3, 4, 5]
注意事项:
- slice() 不会修改原数组,而是返回一个新数组
- 如果省略第二个参数,则提取到数组末尾
- 可以使用负索引,表示从数组末尾倒数
- 常用于创建数组的浅拷贝
const copy = arr.slice()
10. splice() - 添加/删除数组元素
使用场景:当你需要在数组中添加或删除元素时。
示例代码:
// 删除元素
const numbers = [1, 2, 3, 4, 5];
const removed = numbers.splice(2, 2); // 从索引2开始删除2个元素
console.log(numbers); // 输出: [1, 2, 5]
console.log(removed); // 输出: [3, 4]// 替换元素
const fruits = ["苹果", "香蕉", "橙子", "葡萄"];
fruits.splice(1, 2, "桃子", "西瓜"); // 从索引1开始删除2个元素,并添加新元素
console.log(fruits); // 输出: ["苹果", "桃子", "西瓜", "葡萄"]// 插入元素(不删除)
const colors = ["红", "绿", "蓝"];
colors.splice(1, 0, "黄", "紫"); // 在索引1处插入元素,不删除
console.log(colors); // 输出: ["红", "黄", "紫", "绿", "蓝"]
注意事项:
- splice() 会修改原数组
- 返回被删除的元素组成的数组
- 功能强大,可以同时执行删除和添加操作
- 第一个参数是起始索引,第二个参数是删除元素的个数,后面的参数是要添加的元素
11. includes() - 检查数组是否包含某个元素
使用场景:当你需要检查数组是否包含某个特定值时。
示例代码:
const numbers = [1, 2, 3, 4, 5];console.log(numbers.includes(3)); // 输出: true
console.log(numbers.includes(6)); // 输出: false// 从指定索引开始搜索
console.log(numbers.includes(1, 1)); // 输出: false// 检查字符串数组
const fruits = ["苹果", "香蕉", "橙子"];
const hasBanana = fruits.includes("香蕉");
console.log(hasBanana); // 输出: true// 实际应用:权限检查
const userRoles = ["user", "editor"];
const canPublish = userRoles.includes("editor") || userRoles.includes("admin");
console.log(canPublish); // 输出: true
注意事项:
- ES7 (ES2016) 中新增的方法
- 对于简单类型的值比 indexOf() 更直观
- 可以检测 NaN,而 indexOf() 不行
- 第二个参数可以指定开始搜索的位置
12. flat() 和 flatMap() - 数组扁平化
使用场景:当你需要将嵌套数组扁平化为一维数组时。
示例代码:
// 扁平化一级嵌套数组
const nestedArray = [1, 2, [3, 4], 5, [6, 7]];
const flattened = nestedArray.flat();
console.log(flattened); // 输出: [1, 2, 3, 4, 5, 6, 7]// 扁平化多级嵌套数组
const deeplyNested = [1, [2, [3, [4, 5]]]];
const flattenedOneLevel = deeplyNested.flat();
console.log(flattenedOneLevel); // 输出: [1, 2, [3, [4, 5]]]const flattenedAll = deeplyNested.flat(Infinity);
console.log(flattenedAll); // 输出: [1, 2, 3, 4, 5]// flatMap():先映射后扁平化
const sentences = ["Hello world", "JavaScript is fun"];
const words = sentences.flatMap((sentence) => sentence.split(" "));
console.log(words); // 输出: ["Hello", "world", "JavaScript", "is", "fun"]
注意事项:
- ES10 (ES2019) 中新增的方法
- flat() 可以指定扁平化的层级,默认为 1
- flat(Infinity) 可以完全扁平化任意深度的嵌套数组
- flatMap() 相当于先执行 map() 然后执行 flat(1),效率更高
13. push() 和 pop() - 栈操作
使用场景:当你需要将数组作为栈使用,进行后进先出(LIFO)操作时。
示例代码:
const stack = [];// 添加元素到栈顶(数组末尾)
stack.push("A");
stack.push("B");
stack.push("C");
console.log(stack); // 输出: ["A", "B", "C"]// 移除栈顶元素
const topItem = stack.pop();
console.log(topItem); // 输出: "C"
console.log(stack); // 输出: ["A", "B"]// 实现撤销功能
const history = [];
function performAction(action) {console.log(`执行操作: ${action}`);history.push(action);
}function undo() {const action = history.pop();if (action) {console.log(`撤销操作: ${action}`);} else {console.log("没有操作可以撤销");}
}performAction("创建文件");
performAction("编辑文件");
undo(); // 输出: 撤销操作: 编辑文件
undo(); // 输出: 撤销操作: 创建文件
undo(); // 输出: 没有操作可以撤销
注意事项:
- push() 和 pop() 会修改原数组
- push() 可以一次添加多个元素
arr.push(1, 2, 3)
- push() 返回添加元素后数组的新长度
- pop() 返回被移除的元素,如果数组为空则返回 undefined
14. unshift() 和 shift() - 队列操作
使用场景:当你需要将数组作为队列使用,进行先进先出(FIFO)操作时。
示例代码:
const queue = [];// 添加元素到队列末尾
queue.push("A");
queue.push("B");
queue.push("C");
console.log(queue); // 输出: ["A", "B", "C"]// 从队列头部移除元素
const firstItem = queue.shift();
console.log(firstItem); // 输出: "A"
console.log(queue); // 输出: ["B", "C"]// 在数组头部添加元素
queue.unshift("X");
console.log(queue); // 输出: ["X", "B", "C"]// 实际应用:任务队列
const taskQueue = [];function addTask(task) {taskQueue.push(task);console.log(`添加任务: ${task}`);
}function processNextTask() {if (taskQueue.length > 0) {const task = taskQueue.shift();console.log(`处理任务: ${task}`);return task;} else {console.log("没有任务可以处理");return null;}
}addTask("发送邮件");
addTask("更新数据库");
addTask("生成报告");
processNextTask(); // 输出: 处理任务: 发送邮件
processNextTask(); // 输出: 处理任务: 更新数据库
注意事项:
- unshift() 和 shift() 会修改原数组
- 这些操作在大型数组上可能会比较慢,因为需要移动所有元素
- unshift() 可以一次添加多个元素
arr.unshift(1, 2, 3)
- unshift() 返回添加元素后数组的新长度
- shift() 返回被移除的元素,如果数组为空则返回 undefined
String 字符串
1. split() - 分割字符串
使用场景:当你需要将字符串分割成数组时。
示例代码:
// 按空格分割句子
const sentence = "JavaScript 是一门很棒的语言";
const words = sentence.split(" ");
console.log(words); // 输出: ["JavaScript", "是一门很棒的语言"]// 分割CSV数据
const csvData = "张三,25,北京";
const personInfo = csvData.split(",");
console.log(personInfo); // 输出: ["张三", "25", "北京"]
注意事项:
- 如果分隔符是空字符串,则会将字符串分割成单个字符的数组
- 可以通过第二个参数限制返回数组的最大长度
2. substring() 和 slice() - 提取子字符串
使用场景:当你需要获取字符串的一部分时。
示例代码:
const text = "JavaScript编程";// 使用 substring(起始索引, 结束索引)
console.log(text.substring(0, 10)); // 输出: "JavaScript"// 使用 slice(起始索引, 结束索引)
console.log(text.slice(0, 10)); // 输出: "JavaScript"
console.log(text.slice(-3)); // 输出: "编程" (负数索引从后往前数)
注意事项:
- substring() 不接受负索引,而 slice() 接受负索引
- 如果省略第二个参数,两者都会提取到字符串末尾
- substring() 会把较小的参数作为开始索引,较大的作为结束索引
3. replace() - 替换字符串
使用场景:当你需要替换字符串中的某些内容时。
示例代码:
// 替换第一个匹配项
const text = "我喜欢吃苹果,苹果很好吃";
const newText = text.replace("苹果", "香蕉");
console.log(newText); // 输出: "我喜欢吃香蕉,苹果很好吃"// 使用正则表达式替换所有匹配项
const allReplaced = text.replace(/苹果/g, "香蕉");
console.log(allReplaced); // 输出: "我喜欢吃香蕉,香蕉很好吃"
注意事项:
- replace() 默认只替换第一个匹配项
- 要替换所有匹配项,需要使用正则表达式和全局标志 g
- 原字符串不会被修改,而是返回一个新字符串
4. toLowerCase() 和 toUpperCase() - 大小写转换
使用场景:当你需要统一字符串的大小写格式时。
示例代码:
const text = "Hello World";// 转换为小写
const lowerCase = text.toLowerCase();
console.log(lowerCase); // 输出: "hello world"// 转换为大写
const upperCase = text.toUpperCase();
console.log(upperCase); // 输出: "HELLO WORLD"// 实际应用:不区分大小写的比较
function compareIgnoreCase(str1, str2) {return str1.toLowerCase() === str2.toLowerCase();
}console.log(compareIgnoreCase("Hello", "hello")); // 输出: true
console.log(compareIgnoreCase("Hello", "world")); // 输出: false
注意事项:
- 原字符串不会被修改,而是返回一个新字符串
- 这些方法只影响字母字符,数字和符号不受影响
- 某些语言可能需要特殊的本地化处理
5. trim() 和其变体 - 去除空白
使用场景:当你需要删除字符串开头和结尾的空白字符时。
示例代码:
const text = " Hello World ";// 删除首尾空白
const trimmed = text.trim();
console.log(trimmed); // 输出: "Hello World"// 仅删除开头空白
const trimmedStart = text.trimStart(); // 也可以用 trimLeft()
console.log(trimmedStart); // 输出: "Hello World "// 仅删除结尾空白
const trimmedEnd = text.trimEnd(); // 也可以用 trimRight()
console.log(trimmedEnd); // 输出: " Hello World"// 实际应用:表单输入清理
function cleanInput(input) {return input.trim();
}console.log(cleanInput(" user@example.com ")); // 输出: "user@example.com"
注意事项:
- 原字符串不会被修改,而是返回一个新字符串
- trimStart() 和 trimEnd() 是 ES2019 新增的方法
- 空白字符包括空格、制表符、换行符等
- 用户输入验证前通常应该先 trim()
6. padStart() 和 padEnd() - 填充字符串
使用场景:当你需要将字符串填充到指定长度时。
示例代码:
// 数字前面补零
const num = "5";
const paddedNum = num.padStart(2, "0");
console.log(paddedNum); // 输出: "05"// 信用卡号码遮蔽
const creditCard = "1234567890123456";
const lastFour = creditCard.slice(-4);
const masked = lastFour.padStart(creditCard.length, "*");
console.log(masked); // 输出: "************3456"// 右侧填充
const text = "Hello";
const paddedRight = text.padEnd(10, "-");
console.log(paddedRight); // 输出: "Hello-----"// 实际应用:表格对齐
const data = ["名称", "价格", "库存"];
const formatted = data.map((item) => item.padEnd(10, " "));
console.log(formatted.join(" | ")); // 输出: "名称 | 价格 | 库存 "
注意事项:
- ES8 (ES2017) 中新增的方法
- 如果原字符串长度已经大于或等于指定长度,则返回原字符串
- 填充字符串如果过长会被截断
7. includes(), startsWith() 和 endsWith() - 字符串检查
使用场景:当你需要检查字符串是否包含、以某内容开头或结尾时。
示例代码:
const sentence = "JavaScript是Web开发中最流行的语言之一";// 检查是否包含某个子字符串
console.log(sentence.includes("Web")); // 输出: true
console.log(sentence.includes("Python")); // 输出: false// 检查是否以某个子字符串开头
console.log(sentence.startsWith("JavaScript")); // 输出: true
console.log(sentence.startsWith("Web", 10)); // 输出: true (从索引10开始检查)// 检查是否以某个子字符串结尾
console.log(sentence.endsWith("之一")); // 输出: true
console.log(sentence.endsWith("JavaScript", 10)); // 输出: true (检查前10个字符)// 实际应用:文件类型检查
function isImageFile(filename) {return (filename.toLowerCase().endsWith(".jpg") ||filename.toLowerCase().endsWith(".png") ||filename.toLowerCase().endsWith(".gif"));
}console.log(isImageFile("photo.JPG")); // 输出: true
console.log(isImageFile("document.pdf")); // 输出: false
注意事项:
- ES6 中新增的方法
- 这些方法都可以指定开始搜索的位置
- 区分大小写,如果需要不区分大小写,可以先转换为小写
- 比 indexOf() 更直观和语义化
8. repeat() - 重复字符串
使用场景:当你需要将字符串重复多次时。
示例代码:
// 简单重复
const star = "*";
console.log(star.repeat(5)); // 输出: "*****"// 创建分隔线
console.log("-".repeat(20)); // 输出: "--------------------"// 缩进处理
function indent(level) {return " ".repeat(level * 2);
}const code ="function hello() {\n" + indent(1) + "console.log('Hello');\n" + "}";
console.log(code);
// 输出:
// function hello() {
// console.log('Hello');
// }// 实际应用:简单进度条
function progressBar(progress, total) {const percentage = Math.floor((progress / total) * 10);return ("[" +"=".repeat(percentage) +" ".repeat(10 - percentage) +"] " +percentage * 10 +"%");
}console.log(progressBar(3, 10)); // 输出: "[=== ] 30%"
console.log(progressBar(7, 10)); // 输出: "[======= ] 70%"
注意事项:
- ES6 中新增的方法
- 参数必须是正整数,否则会抛出错误
- 如果参数为 0,则返回空字符串
9. charAt() 和 charCodeAt() - 字符处理
使用场景:当你需要处理字符串中的单个字符时。
示例代码:
const text = "Hello, 世界!";// 获取指定位置的字符
console.log(text.charAt(0)); // 输出: "H"
console.log(text.charAt(7)); // 输出: "世"// 获取指定位置字符的 Unicode 编码
console.log(text.charCodeAt(0)); // 输出: 72 (H的Unicode值)
console.log(text.charCodeAt(7)); // 输出: 19990 (世的Unicode值)// 获取完整的 Unicode 码点(支持表情符号等)
console.log("😀".codePointAt(0)); // 输出: 128512// 实际应用:简单加密
function simpleEncrypt(text, key) {return Array.from(text).map((char) => String.fromCharCode(char.charCodeAt(0) + key)).join("");
}function simpleDecrypt(encrypted, key) {return Array.from(encrypted).map((char) => String.fromCharCode(char.charCodeAt(0) - key)).join("");
}const original = "Hello";
const encrypted = simpleEncrypt(original, 5);
console.log(encrypted); // 输出加密后的文本
console.log(simpleDecrypt(encrypted, 5)); // 输出: "Hello"
注意事项:
- charAt() 总是返回一个字符,如果索引超出范围则返回空字符串
- charCodeAt() 返回 0 到 65535 之间的整数,表示 UTF-16 编码
- 对于 Unicode 码点大于 0xFFFF 的字符(如表情符号),应该使用 codePointAt()
- ES6 可以使用方括号表示法 text[0] 访问字符,但索引超出时返回 undefined
10. concat() - 连接字符串
使用场景:当你需要连接多个字符串时。
示例代码:
const firstName = "张";
const lastName = "三";// 连接两个字符串
const fullName = firstName.concat(lastName);
console.log(fullName); // 输出: "张三"// 连接多个字符串
const greeting = "你好, ".concat(firstName,lastName,"!"," 欢迎访问我们的网站。"
);
console.log(greeting); // 输出: "你好, 张三! 欢迎访问我们的网站。"// 等价的 + 操作符
const greetingWithPlus ="你好, " + firstName + lastName + "!" + " 欢迎访问我们的网站。";
console.log(greetingWithPlus); // 输出: "你好, 张三! 欢迎访问我们的网站。"
注意事项:
- 原字符串不会被修改,而是返回一个新字符串
- 虽然 concat() 可以连接多个字符串,但在现代 JavaScript 中,通常使用模板字符串或 + 操作符更常见
- 模板字符串通常更易读:`你好, f i r s t N a m e {firstName} firstName{lastName}! 欢迎访问我们的网站。`
11. match() 和 matchAll() - 正则表达式匹配
使用场景:当你需要使用正则表达式查找字符串中的匹配项时。
示例代码:
// 使用 match() 找到所有匹配项
const text = "我的电话号码是 13912345678 和 13887654321";
const phoneMatches = text.match(/1\d{10}/g);
console.log(phoneMatches); // 输出: ["13912345678", "13887654321"]// 获取捕获组
const dateText = "今天是 2023-10-15,明天是 2023-10-16";
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const match = dateText.match(dateRegex);
console.log(match[0]); // 输出: "2023-10-15" (完整匹配)
console.log(match[1]); // 输出: "2023" (第一个捕获组)
console.log(match[2]); // 输出: "10" (第二个捕获组)
console.log(match[3]); // 输出: "15" (第三个捕获组)// 使用 matchAll() 获取所有匹配和捕获组
const text2 = "张三的生日是 1990-01-15,李四的生日是 1985-07-22";
const dateRegex2 = /(\w+)的生日是 (\d{4})-(\d{2})-(\d{2})/g;
const matches = [...text2.matchAll(dateRegex2)];matches.forEach((match) => {console.log(`姓名: ${match[1]}, 出生年: ${match[2]}, 月: ${match[3]}, 日: ${match[4]}`);
});
// 输出:
// 姓名: 张三, 出生年: 1990, 月: 01, 日: 15
// 姓名: 李四, 出生年: 1985, 月: 07, 日: 22
注意事项:
- match() 与不带 g 标志的正则表达式使用时返回详细信息(包括捕获组)
- match() 与带 g 标志的正则表达式使用时返回所有匹配的数组,但不包含捕获组
- matchAll() 是 ES2020 新增的方法,返回一个迭代器,需要使用 for…of 或扩展运算符消费
- matchAll() 同时提供匹配项和捕获组,非常适合复杂的正则匹配需求
12. search() - 查找字符串位置
使用场景:当你需要查找字符串中某个模式第一次出现的位置时。
示例代码:
const text = "JavaScript是一门强大的编程语言";// 查找字符串位置
const position = text.search("强大");
console.log(position); // 输出: 13// 使用正则表达式
const digitPosition = "abc123def".search(/\d+/);
console.log(digitPosition); // 输出: 3// 查找不存在的内容
const notFound = text.search("Python");
console.log(notFound); // 输出: -1// 不区分大小写的搜索
const caseInsensitive = "Hello World".search(/world/i);
console.log(caseInsensitive); // 输出: 6
注意事项:
- 返回第一个匹配的位置,如果没有找到则返回 -1
- 只能接受正则表达式或可以转换为正则表达式的参数
- 与 indexOf() 类似,但 search() 可以使用更复杂的正则表达式模式
- 不支持全局搜索,总是返回第一个匹配项的位置
Object 对象
1. Object.keys() - 获取对象的所有键
使用场景:当你需要获取对象的所有属性名时。
示例代码:
const person = {name: "张三",age: 30,city: "上海",
};const keys = Object.keys(person);
console.log(keys); // 输出: ["name", "age", "city"]// 结合 forEach 遍历对象
Object.keys(person).forEach((key) => {console.log(`${key}: ${person[key]}`);
});
// 输出:
// name: 张三
// age: 30
// city: 上海
注意事项:
- 只返回对象自身的可枚举属性
- 返回的数组顺序与属性在对象中的顺序一致
- 可以用于检查对象是否为空:
Object.keys(obj).length === 0
2. Object.values() - 获取对象的所有值
使用场景:当你只关心对象的属性值而不关心属性名时。
示例代码:
const person = {name: "张三",age: 30,city: "上海",
};const values = Object.values(person);
console.log(values); // 输出: ["张三", 30, "上海"]// 计算对象中数值属性的总和
const scores = { math: 95, english: 88, history: 76 };
const total = Object.values(scores).reduce((sum, score) => sum + score, 0);
console.log(total); // 输出: 259
注意事项:
- 只返回对象自身的可枚举属性的值
- ES2017 (ES8) 中新增的方法,注意兼容性
3. Object.entries() - 获取键值对数组
使用场景:当你需要同时操作对象的键和值时。
示例代码:
const person = {name: "张三",age: 30,city: "上海",
};const entries = Object.entries(person);
console.log(entries);
// 输出: [["name", "张三"], ["age", 30], ["city", "上海"]]// 遍历键值对
Object.entries(person).forEach(([key, value]) => {console.log(`${key}: ${value}`);
});// 转换为Map对象
const personMap = new Map(Object.entries(person));
console.log(personMap.get("name")); // 输出: "张三"
注意事项:
- 只返回对象自身的可枚举属性的键值对
- ES2017 (ES8) 中新增的方法,注意兼容性
- 常用于对象到 Map 的转换
4. Object.assign() - 合并对象
使用场景:当你需要将一个或多个源对象的属性复制到目标对象时。
示例代码:
// 合并对象
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { c: 5, d: 6 };const result = Object.assign(target, source1, source2);
console.log(target); // 输出: { a: 1, b: 3, c: 5, d: 6 }
console.log(result === target); // 输出: true (修改的是同一个对象)// 创建新对象而不修改原对象
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 });
console.log(original); // 输出: { a: 1, b: 2 }
console.log(copy); // 输出: { a: 1, b: 2, c: 3 }// 默认值设置
function processOptions(options) {const defaults = {timeout: 1000,cache: true,silent: false,};return Object.assign({}, defaults, options);
}console.log(processOptions({ timeout: 2000 }));
// 输出: { timeout: 2000, cache: true, silent: false }
注意事项:
- 修改目标对象并返回它
- 如果有同名属性,后面的会覆盖前面的
- 只复制可枚举属性
- 执行的是浅拷贝,不会克隆嵌套对象
- ES6 新增方法,现代开发中可以使用对象展开运算符替代:
{...obj1, ...obj2}
5. Object.create() - 创建新对象
使用场景:当你需要创建一个新对象,并指定其原型对象时。
示例代码:
// 使用现有对象作为新对象的原型
const person = {isHuman: true,printInfo: function () {console.log(`我叫${this.name},我是${this.isHuman ? "人类" : "非人类"}`);},
};const student = Object.create(person);
student.name = "小明"; // 添加属性
student.isHuman = true; // 覆盖继承的属性
student.printInfo(); // 输出: "我叫小明,我是人类"// 使用null作为原型创建无原型对象
const noProto = Object.create(null);
console.log(noProto.toString); // 输出: undefined (没有继承Object.prototype方法)// 创建对象并定义属性
const config = Object.create(null, {debug: {value: true,writable: false,enumerable: true,},version: {value: "1.0.0",enumerable: true,},
});console.log(config.debug); // 输出: true
console.log(config.version); // 输出: "1.0.0"
注意事项:
- 可以指定新对象的原型对象
- 用 Object.create(null) 创建的对象没有继承任何属性和方法
- 可以通过第二个参数定义对象的属性及其特性
- 是实现对象继承的有效方式
6. Object.freeze() 和 Object.seal() - 对象不可变性
使用场景:当你需要防止对象被修改时。
示例代码:
// Object.freeze() - 完全冻结对象
const frozenObj = {prop: 42,nested: { value: "可以修改" },
};Object.freeze(frozenObj);// 尝试修改
frozenObj.prop = 100; // 不起作用
frozenObj.newProp = "新属性"; // 不起作用
delete frozenObj.prop; // 不起作用console.log(frozenObj.prop); // 输出: 42
console.log(frozenObj.newProp); // 输出: undefined// 注意:嵌套对象不受影响
frozenObj.nested.value = "已修改";
console.log(frozenObj.nested.value); // 输出: "已修改"// Object.seal() - 封闭对象(可以修改现有属性值)
const sealedObj = { x: 1, y: 2 };
Object.seal(sealedObj);sealedObj.x = 10; // 可以修改
sealedObj.z = 3; // 不起作用
delete sealedObj.y; // 不起作用console.log(sealedObj); // 输出: { x: 10, y: 2 }// 检查对象状态
console.log(Object.isFrozen(frozenObj)); // 输出: true
console.log(Object.isSealed(sealedObj)); // 输出: true
注意事项:
- Object.freeze() 使对象不可修改、不可添加/删除属性、不可修改属性特性
- Object.seal() 使对象不可添加/删除属性,但可以修改现有属性值
- 这些方法只影响对象的顶层属性,嵌套对象不受影响
- 在严格模式下,尝试修改冻结/封闭对象会抛出 TypeError
7. Object.fromEntries() - 将键值对转换为对象
使用场景:当你有一个键值对数组或 Map 对象,需要转换为普通对象时。
示例代码:
// 从键值对数组创建对象
const entries = [["name", "张三"],["age", 30],["city", "北京"],
];const person = Object.fromEntries(entries);
console.log(person); // 输出: { name: '张三', age: 30, city: '北京' }// 从Map创建对象
const map = new Map();
map.set("name", "李四");
map.set("age", 25);const mapObject = Object.fromEntries(map);
console.log(mapObject); // 输出: { name: '李四', age: 25 }// 实际应用:URL查询参数转对象
const queryString = "name=张三&age=30&city=北京";
const params = new URLSearchParams(queryString);
const paramsObject = Object.fromEntries(params);console.log(paramsObject); // 输出: { name: '张三', age: '30', city: '北京' }
注意事项:
- ES2019 (ES10) 新增方法
- 是 Object.entries() 的逆操作
- 接受任何实现了迭代器接口的对象,比如数组、Map 等
- 对于重复的键,后面的值会覆盖前面的值
8. Object.defineProperty() 和 Object.defineProperties() - 定义属性
使用场景:当你需要精确地定义对象属性及其特性时。
示例代码:
// 定义单个属性
const product = {};Object.defineProperty(product, "name", {value: "手机",writable: false, // 不可修改enumerable: true, // 可枚举configurable: false, // 不可删除或重新配置
});Object.defineProperty(product, "price", {value: 1999,writable: true,enumerable: true,
});// 尝试修改
product.name = "笔记本"; // 不起作用
product.price = 2999; // 可以修改console.log(product.name); // 输出: "手机"
console.log(product.price); // 输出: 2999// 定义多个属性
const user = {};Object.defineProperties(user, {firstName: {value: "张",writable: true,enumerable: true,},lastName: {value: "三",writable: true,enumerable: true,},fullName: {get() {return `${this.firstName}${this.lastName}`;},enumerable: true,},age: {value: 30,writable: true,enumerable: false, // 不会在循环中显示},
});console.log(user.fullName); // 输出: "张三"
console.log(Object.keys(user)); // 输出: ["firstName", "lastName", "fullName"] (不包含age)
注意事项:
- 允许精确控制属性特性:可写性(writable)、可枚举性(enumerable)、可配置性(configurable)
- 可以定义访问器属性(getter/setter)
- 默认情况下,通过这些方法定义的属性都是不可写、不可枚举、不可配置的
- 可以使用 Object.getOwnPropertyDescriptor() 检查属性特性
9. Object.getPrototypeOf() 和 Object.setPrototypeOf() - 原型操作
使用场景:当你需要获取或设置对象的原型时。
示例代码:
// 获取对象的原型
const arr = [];
const proto = Object.getPrototypeOf(arr);
console.log(proto === Array.prototype); // 输出: true// 设置对象的原型
const animal = {speak() {console.log(`${this.name}发出声音`);},
};const dog = {name: "旺财",bark() {console.log("汪汪!");},
};// 设置dog的原型为animal
Object.setPrototypeOf(dog, animal);dog.speak(); // 输出: "旺财发出声音"
dog.bark(); // 输出: "汪汪!"// 检查原型链
function isInPrototypeChain(obj, constructor) {let proto = Object.getPrototypeOf(obj);while (proto !== null) {if (proto === constructor.prototype) return true;proto = Object.getPrototypeOf(proto);}return false;
}console.log(isInPrototypeChain([], Array)); // 输出: true
console.log(isInPrototypeChain({}, Array)); // 输出: false
注意事项:
- Object.setPrototypeOf() 会影响性能,应避免频繁使用
- 更好的方式是使用 Object.create() 创建具有特定原型的新对象
- 在现代 JavaScript 中,可以使用
__proto__
属性,但它已被废弃,不推荐使用 - 这些方法主要用于框架和库开发,普通应用开发少用
10. Object.is() - 值比较
使用场景:当你需要比较两个值是否相同,包括处理一些特殊情况时。
示例代码:
// 基本比较
console.log(Object.is(5, 5)); // 输出: true
console.log(Object.is("hello", "hello")); // 输出: true
console.log(Object.is([], [])); // 输出: false (不同对象)// 与 === 运算符的区别
console.log(+0 === -0); // 输出: true
console.log(Object.is(+0, -0)); // 输出: falseconsole.log(NaN === NaN); // 输出: false
console.log(Object.is(NaN, NaN)); // 输出: true// 对象引用
const obj = { a: 1 };
const sameObj = obj;
console.log(Object.is(obj, sameObj)); // 输出: true// 实际应用:React的状态比较
function checkIfStateChanged(prevState, nextState) {// 浅比较对象中的每个属性if (Object.keys(prevState).length !== Object.keys(nextState).length) {return true;}return Object.keys(prevState).some((key) => !Object.is(prevState[key], nextState[key]));
}const oldState = { count: 5, name: "张三" };
const newState = { count: 5, name: "李四" };
console.log(checkIfStateChanged(oldState, newState)); // 输出: true
注意事项:
- ES6 新增方法
- 与 === 运算符的主要区别:
- Object.is(NaN, NaN) 返回 true
- Object.is(+0, -0) 返回 false
- 对于对象仍然是比较引用,不比较内容
- 适用于需要精确比较的场景,如状态管理
Date 日期
1. new Date() - 创建日期对象
使用场景:当你需要处理日期和时间时。
示例代码:
// 创建当前日期时间的对象
const now = new Date();
console.log(now); // 输出当前时间,如: Tue Oct 12 2023 15:30:45 GMT+0800// 创建特定日期的对象
const christmas = new Date(2023, 11, 25); // 月份是0-11,所以12月是11
console.log(christmas); // 输出: Mon Dec 25 2023 00:00:00 GMT+0800// 从时间戳创建日期对象
const timestamp = 1609459200000; // 2021-01-01 00:00:00
const newYear = new Date(timestamp);
console.log(newYear); // 输出: Fri Jan 01 2021 00:00:00 GMT+0800
注意事项:
- JavaScript 中月份从 0 开始计数(0 表示一月,11 表示十二月)
- 日期对象创建后,可以使用各种方法获取或设置其组成部分
2. 格式化日期
使用场景:当你需要以特定格式显示日期时。
示例代码:
const today = new Date();// 获取各部分
const year = today.getFullYear();
const month = today.getMonth() + 1; // 月份需要+1,因为从0开始
const day = today.getDate();
const hours = today.getHours();
const minutes = today.getMinutes();
const seconds = today.getSeconds();// 自定义格式化
const formattedDate = `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`;
console.log(formattedDate); // 输出类似: 2023年10月12日 15:30:45// 使用 toLocaleDateString 方法
const localDate = today.toLocaleDateString("zh-CN", {year: "numeric",month: "long",day: "numeric",weekday: "long",
});
console.log(localDate); // 输出类似: 2023年10月12日星期四
注意事项:
- 获取月份时记得加 1,因为月份从 0 开始
- 为了保持格式一致,可能需要对个位数补零
- toLocaleDateString 方法提供了丰富的本地化格式选项
3. 日期计算
使用场景:当你需要计算日期差异或进行日期操作时。
示例代码:
// 计算两个日期之间的天数差
const date1 = new Date("2023-01-01");
const date2 = new Date("2023-01-15");
const diffTime = Math.abs(date2 - date1);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
console.log(`相差 ${diffDays} 天`); // 输出: 相差 14 天// 添加天数
const today = new Date();
const futureDate = new Date(today);
futureDate.setDate(today.getDate() + 30);
console.log(`30天后是: ${futureDate.toLocaleDateString()}`);
注意事项:
- 日期对象可以相减,结果是毫秒数
- setDate(), setMonth() 等方法可以用于修改日期
- 注意处理月末日期,如 1 月 31 日加一个月可能变成 3 月某一天
4. 日期比较
使用场景:当你需要比较两个日期的先后或是否相等时。
示例代码:
// 比较日期的先后
const date1 = new Date("2023-05-10");
const date2 = new Date("2023-10-15");
const date3 = new Date("2023-05-10");// 使用比较运算符
console.log(date1 < date2); // 输出: true (5月早于10月)
console.log(date1 > date2); // 输出: false// 检查日期是否相等
console.log(date1.getTime() === date3.getTime()); // 输出: true
console.log(date1 === date3); // 输出: false (两个不同的对象)// 判断某个日期是否在两个日期之间
function isBetween(date, start, end) {return date >= start && date <= end;
}const checkDate = new Date("2023-06-15");
console.log(isBetween(checkDate, date1, date2)); // 输出: true// 判断是否为同一天
function isSameDay(date1, date2) {return (date1.getFullYear() === date2.getFullYear() &&date1.getMonth() === date2.getMonth() &&date1.getDate() === date2.getDate());
}console.log(isSameDay(new Date("2023-05-10T10:30:00"), new Date("2023-05-10T18:15:00"))
); // 输出: true
注意事项:
- 日期对象可以直接用 <, >, <=, >= 比较
- 不能用 == 或 === 直接比较日期对象相等,因为它们是引用类型
- 比较日期相等应使用 getTime() 方法或自定义方法
5. 获取特定日期部分
使用场景:当你需要获取日期的特定部分(年、月、日、星期几等)时。
示例代码:
const date = new Date("2023-05-20T15:30:45.500Z");// 获取年、月、日
console.log(date.getFullYear()); // 输出: 2023
console.log(date.getMonth()); // 输出: 4 (5月)
console.log(date.getDate()); // 输出: 20// 获取时、分、秒、毫秒
console.log(date.getHours()); // 输出: 23 (假设东八区)
console.log(date.getMinutes()); // 输出: 30
console.log(date.getSeconds()); // 输出: 45
console.log(date.getMilliseconds()); // 输出: 500// 获取星期几 (0-6,0代表周日)
console.log(date.getDay()); // 输出: 6 (周六)// 获取时间戳(毫秒数)
console.log(date.getTime()); // 输出: 1684596645500// 实际应用:获取本月天数
function getDaysInMonth(year, month) {// month传入的是1-12,需要转换为0-11return new Date(year, month, 0).getDate();
}console.log(getDaysInMonth(2023, 2)); // 输出: 28 (2023年2月有28天)
console.log(getDaysInMonth(2024, 2)); // 输出: 29 (闰年)
注意事项:
- get 方法返回本地时间的部分,有对应的 getUTC 方法返回 UTC 时间的部分
- getMonth() 返回 0-11,代表 1-12 月
- getDay() 返回 0-6,代表周日-周六
6. 设置特定日期部分
使用场景:当你需要修改日期的特定部分时。
示例代码:
// 创建日期
let date = new Date("2023-05-20");// 设置年、月、日
date.setFullYear(2024);
console.log(date); // 输出: Mon May 20 2024 ...date.setMonth(0); // 设置为1月
console.log(date); // 输出: Sat Jan 20 2024 ...date.setDate(15);
console.log(date); // 输出: Mon Jan 15 2024 ...// 设置时、分、秒、毫秒
date.setHours(10);
date.setMinutes(30);
date.setSeconds(0);
date.setMilliseconds(0);
console.log(date); // 输出: Mon Jan 15 2024 10:30:00 ...// 使用毫秒数设置日期
date.setTime(1672502400000); // 2023-01-01 00:00:00
console.log(date); // 输出: Sun Jan 01 2023 00:00:00 ...// 实际应用:将日期设置为本月最后一天
function setToLastDayOfMonth(date) {// 设置为下个月的第0天,即本月最后一天date.setMonth(date.getMonth() + 1, 0);return date;
}const someDate = new Date("2023-05-15");
setToLastDayOfMonth(someDate);
console.log(someDate); // 输出: Wed May 31 2023 ...
注意事项:
- set 方法会修改原日期对象
- 设置超出范围的值会导致日期自动调整(如设置 2 月 31 日会变成 3 月某一天)
- 有对应的 setUTC 方法设置 UTC 时间的部分
7. 时区和国际化处理
使用场景:当你需要处理不同时区的日期或本地化显示日期时。
示例代码:
// 获取带时区的日期字符串
const date = new Date("2023-05-20T10:30:00Z");// ISO 格式(适合数据交换)
console.log(date.toISOString()); // 输出: 2023-05-20T10:30:00.000Z// 获取时区偏移量(分钟)
const timezoneOffset = date.getTimezoneOffset();
console.log(timezoneOffset); // 输出: -480 (东八区为-480分钟,即-8小时)// 本地化日期格式
console.log(date.toLocaleDateString("zh-CN")); // 输出: 2023/5/20
console.log(date.toLocaleDateString("en-US")); // 输出: 5/20/2023
console.log(date.toLocaleDateString("de-DE")); // 输出: 20.5.2023// 本地化时间格式
console.log(date.toLocaleTimeString("zh-CN")); // 输出: 18:30:00
console.log(date.toLocaleTimeString("en-US")); // 输出: 6:30:00 PM// 完整的本地化日期和时间格式
console.log(date.toLocaleString("zh-CN")); // 输出: 2023/5/20 18:30:00
console.log(date.toLocaleString("en-US")); // 输出: 5/20/2023, 6:30:00 PM// 高级格式化
console.log(date.toLocaleString("zh-CN", {weekday: "long",year: "numeric",month: "long",day: "numeric",hour: "2-digit",minute: "2-digit",second: "2-digit",timeZoneName: "long",})
); // 输出: 2023年5月20日星期六 18:30:00 中国标准时间
注意事项:
- toISOString() 总是返回 UTC 时间的字符串
- 时区偏移量以分钟为单位,正值表示比 UTC 早,负值表示比 UTC 晚
- Intl.DateTimeFormat 提供了更强大的国际化日期格式化能力
Math 数学
1. Math.random() - 生成随机数
使用场景:当你需要生成随机数或随机选择时。
示例代码:
// 生成0到1之间的随机数(不包括1)
const random = Math.random();
console.log(random); // 输出例如: 0.7589021623732578// 生成1到10之间的随机整数
const randomInt = Math.floor(Math.random() * 10) + 1;
console.log(randomInt); // 输出1到10之间的整数// 从数组中随机选择一个元素
const fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"];
const randomIndex = Math.floor(Math.random() * fruits.length);
const randomFruit = fruits[randomIndex];
console.log(`随机水果: ${randomFruit}`);
注意事项:
- Math.random() 生成的是伪随机数,不适用于加密场景
- 生成范围内随机整数的公式:Math.floor(Math.random() * (max - min + 1)) + min
2. Math.round(), Math.floor(), Math.ceil() - 数字取整
使用场景:当你需要对小数进行取整时。
示例代码:
const num = 4.6;// 四舍五入
console.log(Math.round(num)); // 输出: 5
console.log(Math.round(4.4)); // 输出: 4// 向下取整(不大于原数的最大整数)
console.log(Math.floor(num)); // 输出: 4
console.log(Math.floor(-4.6)); // 输出: -5// 向上取整(不小于原数的最小整数)
console.log(Math.ceil(num)); // 输出: 5
console.log(Math.ceil(-4.6)); // 输出: -4
注意事项:
- 注意负数的情况,Math.floor(-4.6) 等于 -5,而不是 -4
- 金融计算中四舍五入可能需要特殊处理,避免二进制浮点数精度问题
3. Math.max() 和 Math.min() - 最大值和最小值
使用场景:当你需要找出一组数字中的最大或最小值时。
示例代码:
// 找出最大值
console.log(Math.max(5, 10, 3, 8, 6)); // 输出: 10// 找出最小值
console.log(Math.min(5, 10, 3, 8, 6)); // 输出: 3// 结合展开运算符找出数组中的最大值
const numbers = [5, 10, 3, 8, 6];
console.log(Math.max(...numbers)); // 输出: 10// 实际应用:确保值在范围内
function clamp(value, min, max) {return Math.min(Math.max(value, min), max);
}
console.log(clamp(15, 0, 10)); // 输出: 10
console.log(clamp(-5, 0, 10)); // 输出: 0
console.log(clamp(5, 0, 10)); // 输出: 5
注意事项:
- 如果传入非数字参数,返回 NaN
- 不传参数时,Math.max() 返回 -Infinity,Math.min() 返回 Infinity
- 要处理数组,需要使用扩展运算符 (…)
4. Math.abs() - 绝对值
使用场景:当你需要获取数字的绝对值(非负值)时。
示例代码:
// 基本用法
console.log(Math.abs(5)); // 输出: 5
console.log(Math.abs(-5)); // 输出: 5
console.log(Math.abs(0)); // 输出: 0// 计算两个数的差值(不关心谁大谁小)
function difference(a, b) {return Math.abs(a - b);
}console.log(difference(10, 5)); // 输出: 5
console.log(difference(5, 10)); // 输出: 5// 判断两个浮点数是否近似相等
function isApproximatelyEqual(a, b, epsilon = 0.0001) {return Math.abs(a - b) < epsilon;
}console.log(isApproximatelyEqual(0.1 + 0.2, 0.3)); // 输出: true
注意事项:
- 传入非数字参数时,会尝试将其转换为数字
- 如果参数无法转换为数字,返回 NaN
- 用于处理方向无关的距离计算
5. Math.pow() 和 Math.sqrt() - 幂运算和平方根
使用场景:当你需要计算幂或平方根时。
示例代码:
// 幂运算(x的y次方)
console.log(Math.pow(2, 3)); // 输出: 8 (2的3次方)
console.log(Math.pow(5, 2)); // 输出: 25 (5的平方)
console.log(Math.pow(4, 0.5)); // 输出: 2 (4的平方根)
console.log(Math.pow(2, -1)); // 输出: 0.5 (2的-1次方,即1/2)// 平方根
console.log(Math.sqrt(9)); // 输出: 3
console.log(Math.sqrt(2)); // 输出: 1.4142135623730951
console.log(Math.sqrt(-1)); // 输出: NaN (负数的平方根在实数范围内不存在)// 计算直角三角形斜边长度(勾股定理)
function calculateHypotenuse(a, b) {return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));// 或者使用 ES6 的 ** 运算符:return Math.sqrt(a ** 2 + b ** 2);
}console.log(calculateHypotenuse(3, 4)); // 输出: 5
注意事项:
- ES6 引入了 ** 运算符,可以替代 Math.pow(),例如 2 ** 3 等同于 Math.pow(2, 3)
- Math.sqrt() 只能计算正数的平方根,对于负数返回 NaN
- 可以使用 Math.pow(x, 1/n) 计算 x 的 n 次方根
6. Math.sin(), Math.cos(), Math.tan() - 三角函数
使用场景:当你需要进行三角函数计算或处理角度和坐标时。
示例代码:
// 基本三角函数(参数为弧度)
console.log(Math.sin(Math.PI / 2)); // 输出: 1 (90度的正弦值)
console.log(Math.cos(Math.PI)); // 输出: -1 (180度的余弦值)
console.log(Math.tan(Math.PI / 4)); // 输出: 0.9999999999999999 (接近1,45度的正切值)// 度数转弧度
function toRadians(degrees) {return degrees * (Math.PI / 180);
}// 弧度转度数
function toDegrees(radians) {return radians * (180 / Math.PI);
}console.log(Math.sin(toRadians(90))); // 输出: 1
console.log(toDegrees(Math.PI)); // 输出: 180// 在圆上计算点的坐标
function getPointOnCircle(centerX, centerY, radius, angleInDegrees) {const angleInRadians = toRadians(angleInDegrees);return {x: centerX + radius * Math.cos(angleInRadians),y: centerY + radius * Math.sin(angleInRadians),};
}const point = getPointOnCircle(100, 100, 50, 60);
console.log(point); // 输出: { x: 125, y: 143.3 } (大约)
注意事项:
- 三角函数的参数是弧度,不是度数(1 弧度 ≈ 57.3 度,1 度 = π/180 弧度)
- Math.PI 常量代表圆周率 π
- JavaScript 还提供了反三角函数:Math.asin(), Math.acos(), Math.atan()
7. Math.log(), Math.exp() - 对数和指数函数
使用场景:当你需要计算自然对数或指数时。
示例代码:
// 自然对数(以e为底)
console.log(Math.log(Math.E)); // 输出: 1 (e的自然对数等于1)
console.log(Math.log(1)); // 输出: 0 (任何底数的0次方等于1,所以1的对数等于0)
console.log(Math.log(10)); // 输出: 2.302585092994046// 以10为底的对数
console.log(Math.log10(100)); // 输出: 2
console.log(Math.log10(1000)); // 输出: 3// 以2为底的对数
console.log(Math.log2(8)); // 输出: 3
console.log(Math.log2(16)); // 输出: 4// 自然指数(e的n次方)
console.log(Math.exp(1)); // 输出: 2.718281828459045 (e的1次方)
console.log(Math.exp(2)); // 输出: 7.3890560989306495 (e的2次方)
console.log(Math.exp(0)); // 输出: 1// 使用场景:复利计算
function calculateCompoundInterest(principal, rate, time) {// A = P * e^(rt)return principal * Math.exp(rate * time);
}console.log(calculateCompoundInterest(1000, 0.05, 10)); // 输出: 1648.7212707001282
注意事项:
- Math.log() 是自然对数(以 e 为底)
- Math.log10() 和 Math.log2() 分别是以 10 和 2 为底的对数
- Math.E 常量表示自然对数的底数 e (约等于 2.718)
- 对数用于处理指数增长的数据,如复利、人口增长等
8. Math.sign(), Math.trunc(), Math.fround() - ES6 新增函数
使用场景:当你需要确定数字的符号、截断小数部分或获取单精度浮点数表示时。
示例代码:
// Math.sign() - 返回数字的符号
console.log(Math.sign(10)); // 输出: 1
console.log(Math.sign(-10)); // 输出: -1
console.log(Math.sign(0)); // 输出: 0
console.log(Math.sign(-0)); // 输出: -0
console.log(Math.sign(NaN)); // 输出: NaN// Math.trunc() - 删除小数部分(与floor不同,不会舍入)
console.log(Math.trunc(3.7)); // 输出: 3
console.log(Math.trunc(-3.7)); // 输出: -3
console.log(Math.floor(-3.7)); // 输出: -4 (向下舍入)// Math.fround() - 返回最接近的32位单精度浮点数表示
console.log(Math.fround(1.337)); // 输出: 1.3370000123977661
console.log(Math.fround(1.5)); // 输出: 1.5// 使用Math.sign()简化代码
function getMovementDirection(velocity) {switch (Math.sign(velocity)) {case 1:return "向前";case -1:return "向后";case 0:return "静止";default:return "无效值";}
}console.log(getMovementDirection(5)); // 输出: "向前"
console.log(getMovementDirection(-3)); // 输出: "向后"
console.log(getMovementDirection(0)); // 输出: "静止"
注意事项:
- 这些方法都是 ES6 新增的
- Math.sign() 返回数字的符号:1, -1, 0, -0 或 NaN
- Math.trunc() 简单地删除小数部分,而不是舍入
- Math.fround() 在处理 WebGL 或需要 32 位浮点数时很有用
9. Math 常量 - 数学常数
使用场景:当你需要使用数学常数进行计算时。
示例代码:
// 圆周率
console.log(Math.PI); // 输出: 3.141592653589793
// 计算圆的面积
const radius = 5;
const area = Math.PI * radius * radius;
console.log(area); // 输出: 78.53981633974483// 自然对数的底(欧拉数)
console.log(Math.E); // 输出: 2.718281828459045
// 连续复利公式
const principal = 1000;
const rate = 0.1;
const years = 5;
const amount = principal * Math.pow(Math.E, rate * years);
console.log(amount); // 输出: 1648.7212707001282// 2的平方根
console.log(Math.SQRT2); // 输出: 1.4142135623730951
// 2的倒数平方根
console.log(Math.SQRT1_2); // 输出: 0.7071067811865476
// 10的自然对数
console.log(Math.LN10); // 输出: 2.302585092994046
// 2的自然对数
console.log(Math.LN2); // 输出: 0.6931471805599453
// 以10为底e的对数
console.log(Math.LOG10E); // 输出: 0.4342944819032518
// 以2为底e的对数
console.log(Math.LOG2E); // 输出: 1.4426950408889634
注意事项:
- 这些常量是只读的,不能被修改
- 它们提供了比手动输入更精确的数学常数
- 在数学计算和科学应用中经常使用
10. 复杂数学计算 - 组合应用
使用场景:当你需要进行复杂的数学计算时。
示例代码:
// 计算距离(两点之间的欧几里得距离)
function distance(x1, y1, x2, y2) {return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}console.log(distance(0, 0, 3, 4)); // 输出: 5// 角度转换
function degreesToRadians(degrees) {return (degrees * Math.PI) / 180;
}function radiansToDegrees(radians) {return (radians * 180) / Math.PI;
}console.log(degreesToRadians(90)); // 输出: 1.5707963267948966
console.log(radiansToDegrees(Math.PI / 4)); // 输出: 45// 生成指定范围内的随机整数数组(不重复)
function generateUniqueRandomNumbers(min, max, count) {if (max - min + 1 < count) {throw new Error("范围太小,无法生成不重复的随机数");}const result = new Set();while (result.size < count) {const randomNum = Math.floor(Math.random() * (max - min + 1)) + min;result.add(randomNum);}return Array.from(result);
}console.log(generateUniqueRandomNumbers(1, 20, 5)); // 输出: 如 [3, 7, 12, 15, 18]// 贝塞尔曲线的点(二次贝塞尔曲线)
function quadraticBezierPoint(p0, p1, p2, t) {const x =Math.pow(1 - t, 2) * p0.x + 2 * (1 - t) * t * p1.x + Math.pow(t, 2) * p2.x;const y =Math.pow(1 - t, 2) * p0.y + 2 * (1 - t) * t * p1.y + Math.pow(t, 2) * p2.y;return { x, y };
}const start = { x: 0, y: 0 };
const control = { x: 50, y: 100 };
const end = { x: 100, y: 0 };
console.log(quadraticBezierPoint(start, control, end, 0.5)); // 输出: { x: 50, y: 50 }
注意事项:
- 复杂计算通常需要组合多个 Math 方法
- 浮点数运算可能存在精度问题,需要小心处理
- 某些复杂的数学运算可能需要使用外部库
- 性能敏感场景下,可以考虑对频繁使用的数学函数进行优化
Promise 异步处理
1. Promise.all() - 并行处理多个异步操作
使用场景:当你需要等待多个异步操作全部完成时。
示例代码:
// 模拟一些异步请求
function fetchUserData() {return new Promise((resolve) => {setTimeout(() => resolve({ name: "张三", age: 25 }), 1000);});
}function fetchUserPosts() {return new Promise((resolve) => {setTimeout(() => resolve(["帖子1", "帖子2", "帖子3"]), 1500);});
}// 同时获取用户数据和帖子
Promise.all([fetchUserData(), fetchUserPosts()]).then(([userData, posts]) => {console.log("用户数据:", userData);console.log("用户帖子:", posts);}).catch((error) => {console.error("一个或多个请求失败:", error);});
注意事项:
- 如果任何一个 Promise 失败,Promise.all() 就会立即失败
- 所有 Promise 都成功后,返回的结果是按照输入顺序排列的数组
- 如果数组为空,Promise.all 会立即完成
2. Promise.race() - 竞态处理
使用场景:当你只关心多个异步操作中最先完成的一个时。
示例代码:
// 带超时的请求
function fetchData() {return new Promise((resolve) => {setTimeout(() => resolve("数据获取成功"), 2000);});
}function timeout(ms) {return new Promise((_, reject) => {setTimeout(() => reject(new Error("请求超时")), ms);});
}// 如果请求时间超过1.5秒,就会超时
Promise.race([fetchData(), timeout(1500)]).then((result) => {console.log(result);}).catch((error) => {console.error(error.message); // 输出: 请求超时});
注意事项:
- Promise.race() 返回的是第一个完成的 Promise 的结果,无论成功或失败
- 如果数组为空,Promise.race 会永远处于 pending 状态
- 常用于实现超时处理或选择最快的资源
3. async/await - 更简洁的异步处理
使用场景:当你想以同步的方式编写异步代码时。
示例代码:
// 模拟异步API调用
function fetchUser(id) {return new Promise((resolve) => {setTimeout(() => {resolve({ id, name: `用户${id}`, age: 20 + id });}, 1000);});
}// 使用async/await处理异步操作
async function getUserInfo(id) {try {console.log("开始获取用户信息...");const user = await fetchUser(id);console.log("用户数据:", user);// 可以使用条件判断if (user.age > 25) {console.log("这是一位成年人");}return user;} catch (error) {console.error("获取用户信息失败:", error);}
}// 调用异步函数
getUserInfo(5).then((userData) => {console.log("处理完成,最终用户数据:", userData);
});
注意事项:
- async 函数总是返回一个 Promise
- await 关键字只能在 async 函数内部使用
- 使用 try/catch 来捕获异步操作中的错误
- 如果有多个独立的异步操作需要并行执行,可以结合 Promise.all 使用
4. Promise.allSettled() - 处理多个异步结果
使用场景:当你需要等待多个异步操作完成,并且不希望某个操作的失败影响其他操作时。
示例代码:
// 定义三个Promise,一个成功,两个失败
const promise1 = Promise.resolve(42);
const promise2 = Promise.reject(new Error("请求失败"));
const promise3 = new Promise((resolve) =>setTimeout(() => resolve("迟到的数据"), 1000)
);Promise.allSettled([promise1, promise2, promise3]).then((results) => {console.log(results);// 输出:// [// { status: "fulfilled", value: 42 },// { status: "rejected", reason: Error: 请求失败 },// { status: "fulfilled", value: "迟到的数据" }// ]// 过滤出成功的结果const successfulResults = results.filter((result) => result.status === "fulfilled").map((result) => result.value);console.log("成功的结果:", successfulResults);// 输出: [42, "迟到的数据"]// 检查哪些操作失败了results.forEach((result, index) => {if (result.status === "rejected") {console.log(`操作 ${index + 1} 失败: ${result.reason}`);}});
});
图解:
注意事项:
- ES2020 新增方法
- 无论 Promise 是成功还是失败,Promise.allSettled() 都会等待所有 Promise 完成
- 返回的结果数组包含每个 Promise 的状态和值/原因
- 适用于需要执行多个独立操作并收集所有结果的场景
5. Promise.any() - 获取第一个成功结果
使用场景:当你只需要获取多个异步操作中第一个成功的结果时。
示例代码:
// 从多个服务器加载数据,只需要第一个成功响应
function fetchFromServer1() {return new Promise((resolve, reject) => {setTimeout(() => reject(new Error("服务器1失败")), 1000);});
}function fetchFromServer2() {return new Promise((resolve) => {setTimeout(() => resolve("服务器2的数据"), 1500);});
}function fetchFromServer3() {return new Promise((resolve) => {setTimeout(() => resolve("服务器3的数据"), 800);});
}Promise.any([fetchFromServer1(), fetchFromServer2(), fetchFromServer3()]).then((firstSuccess) => {console.log("第一个成功的结果:", firstSuccess); // 输出: 服务器3的数据}).catch((error) => {console.log("所有请求都失败了");console.log(error); // 这是一个 AggregateError 对象});// 所有 Promise 都失败的情况
Promise.any([Promise.reject(new Error("失败1")),Promise.reject(new Error("失败2")),Promise.reject(new Error("失败3")),
]).catch((error) => {console.log(error instanceof AggregateError); // 输出: trueconsole.log(error.message); // 输出: All promises were rejectedconsole.log(error.errors); // 输出: [Error: 失败1, Error: 失败2, Error: 失败3]
});
注意事项:
- ES2021 新增方法
- 和 Promise.race() 不同,Promise.any() 会忽略失败的 Promise,只关注成功的
- 当所有 Promise 都失败时,会抛出 AggregateError (一个包含所有失败原因的错误)
- 适用于从多个冗余资源中加载数据的场景
6. Promise.resolve() 和 Promise.reject() - 创建已决议的 Promise
使用场景:当你需要快速创建一个已完成或已拒绝的 Promise 时。
示例代码:
// 创建一个立即完成的 Promise
const resolvedPromise = Promise.resolve("已完成");
resolvedPromise.then((value) => {console.log(value); // 输出: 已完成
});// 创建一个立即拒绝的 Promise
const rejectedPromise = Promise.reject(new Error("出错了"));
rejectedPromise.catch((error) => {console.error(error.message); // 输出: 出错了
});// 将同步函数包装为异步函数
function getValueAsync(value) {return Promise.resolve(value);
}// 根据条件返回成功或失败的 Promise
function fetchData(shouldSucceed) {return shouldSucceed? Promise.resolve({ data: "请求成功" }): Promise.reject(new Error("请求失败"));
}fetchData(true).then((result) => console.log(result)).catch((error) => console.error(error.message));// 处理 thenable 对象
const thenable = {then(resolve, reject) {resolve("来自 thenable 的数据");},
};Promise.resolve(thenable).then((value) => {console.log(value); // 输出: 来自 thenable 的数据
});
注意事项:
- Promise.resolve() 将值包装成一个已完成的 Promise
- Promise.reject() 创建一个已拒绝的 Promise
- 如果传给 Promise.resolve() 的是一个 Promise,它会原样返回
- 如果传给 Promise.resolve() 的是一个 thenable 对象(带 then 方法的对象),它会被转换为 Promise
7. Promise 链式调用 - 连续处理异步操作
使用场景:当你需要按顺序执行一系列依赖前一步结果的异步操作时。
示例代码:
// 模拟获取用户,然后获取用户的帖子,然后获取帖子的评论
function fetchUser(userId) {return new Promise((resolve) => {setTimeout(() => {resolve({ id: userId, name: "用户" + userId });}, 500);});
}function fetchPosts(user) {return new Promise((resolve) => {setTimeout(() => {resolve({user: user,posts: [{ id: 1, title: "第一篇帖子" },{ id: 2, title: "第二篇帖子" },],});}, 500);});
}function fetchComments(post) {return new Promise((resolve) => {setTimeout(() => {resolve({post: post,comments: [{ id: 1, text: "很棒的文章!" },{ id: 2, text: "谢谢分享!" },],});}, 500);});
}// 链式调用
fetchUser(1).then((user) => {console.log("用户:", user);return fetchPosts(user);}).then((result) => {console.log("帖子:", result.posts);return fetchComments(result.posts[0]);}).then((result) => {console.log("评论:", result.comments);}).catch((error) => {console.error("错误:", error);});// 同样的逻辑用 async/await 表达:
async function fetchUserPostsAndComments(userId) {try {const user = await fetchUser(userId);console.log("用户:", user);const postsResult = await fetchPosts(user);console.log("帖子:", postsResult.posts);const commentsResult = await fetchComments(postsResult.posts[0]);console.log("评论:", commentsResult.comments);return commentsResult;} catch (error) {console.error("错误:", error);}
}fetchUserPostsAndComments(1);
注意事项:
- 链式调用中的每个 .then() 都可以返回一个新的 Promise,形成连续的异步操作
- 同一链中的错误处理可以由一个 .catch() 统一处理
- 链式调用代码可能变得冗长,此时 async/await 通常更易读
- 在每个 .then() 中返回值很重要,否则下一个 .then() 将收到 undefined
8. Promise 并发控制 - 限制并发请求数量
使用场景:当你需要处理大量异步任务,但想限制同时执行的任务数量时。
示例代码:
// 模拟异步请求
function fetchData(id) {return new Promise((resolve) => {const delay = Math.floor(Math.random() * 1000) + 500;console.log(`开始请求 ${id},预计 ${delay}ms`);setTimeout(() => {console.log(`请求 ${id} 完成`);resolve(`数据 ${id}`);}, delay);});
}// 并发控制函数
async function concurrentPromises(tasks, maxConcurrent) {const results = [];const executing = new Set();for (const [index, task] of tasks.entries()) {const promise = Promise.resolve().then(() => task());results[index] = promise;// 如果达到最大并发数,等待某个任务完成if (maxConcurrent <= executing.size) {await Promise.race(executing);}// 将当前任务添加到执行集合,并在完成后移除executing.add(promise);promise.then(() => executing.delete(promise));}return Promise.all(results);
}// 准备任务
const tasks = Array.from({ length: 10 }, (_, i) => {return () => fetchData(i + 1);
});// 执行任务,最多同时执行3个
concurrentPromises(tasks, 3).then((results) => {console.log("所有请求完成");console.log(results);
});// 使用队列实现并发控制(另一种方法)
async function requestWithConcurrencyLimit(urls, limit) {const results = [];const queue = [...urls];const executing = [];while (queue.length > 0) {// 从队列中取出下一个URLconst url = queue.shift();// 创建请求Promise并将其包装,以便在完成时从executing数组中移除const p = fetchData(url).then((result) => {executing.splice(executing.indexOf(p), 1);return result;});// 跟踪正在执行的Promiseresults.push(p);executing.push(p);// 如果达到限制,等待一个Promise完成if (executing.length >= limit) {await Promise.race(executing);}}// 等待所有结果return Promise.all(results);
}
注意事项:
- 控制并发对于防止请求过载和资源竞争很重要
- Set 用于跟踪正在执行的 Promise,方便移除完成的任务
- 使用 Promise.race() 来等待任意一个任务完成
- 实际应用中可能需要处理错误和重试逻辑
9. async 迭代器 - 异步遍历数据
使用场景:当你需要异步迭代大量数据或流时。
示例代码:
// 模拟异步数据源
async function* generateData() {for (let i = 1; i <= 5; i++) {// 模拟异步操作await new Promise((resolve) => setTimeout(resolve, 500));yield `数据项 ${i}`;}
}// 使用 for await...of 遍历异步迭代器
async function processData() {console.log("开始处理数据...");for await (const item of generateData()) {console.log("收到:", item);}console.log("数据处理完成");
}processData();// 异步迭代数据库结果
async function* fetchUsers(batchSize = 2) {// 模拟数据库中的用户const allUsers = [{ id: 1, name: "张三" },{ id: 2, name: "李四" },{ id: 3, name: "王五" },{ id: 4, name: "赵六" },{ id: 5, name: "钱七" },];// 批量获取用户for (let i = 0; i < allUsers.length; i += batchSize) {// 模拟数据库查询延迟await new Promise((resolve) => setTimeout(resolve, 1000));const batch = allUsers.slice(i, i + batchSize);console.log(`获取用户批次: ${i / batchSize + 1}`);yield batch;}
}// 处理用户数据
async function processAllUsers() {let userCount = 0;for await (const userBatch of fetchUsers()) {console.log("处理用户批次:", userBatch);userCount += userBatch.length;}console.log(`总共处理了 ${userCount} 个用户`);
}processAllUsers();
注意事项:
- 异步迭代器是 ES2018 的特性
- 使用 async function* 定义异步生成器函数
- 使用 for await…of 循环迭代异步生成的值
- 适用于处理流式数据、分页 API 结果等场景
10. 错误处理和调试 - 处理 Promise 中的错误
使用场景:当你需要在 Promise 链中优雅地处理错误和进行调试时。
示例代码:
// 一个可能出错的异步函数
function riskyOperation(shouldFail = false) {return new Promise((resolve, reject) => {setTimeout(() => {if (shouldFail) {reject(new Error("操作失败"));} else {resolve("操作成功");}}, 500);});
}// 1. 捕获和处理错误
riskyOperation(true).then((result) => {console.log(result);}).catch((error) => {console.error("捕获到错误:", error.message);// 可以返回一个默认值继续链return "默认结果";}).then((result) => {console.log("继续处理:", result);});// 2. 不同级别的错误处理
function operation1() {return riskyOperation(false);
}function operation2() {return riskyOperation(true);
}function operation3() {return riskyOperation(false);
}operation1().then((result) => {console.log("操作1成功:", result);return operation2();}).catch((error) => {console.error("操作2失败:", error.message);// 可以继续执行操作3return operation3();}).then((result) => {console.log("最终结果:", result);}).catch((error) => {console.error("致命错误:", error.message);}).finally(() => {console.log("清理资源...");});// 3. async/await 中的错误处理
async function performOperations() {try {const result1 = await operation1();console.log("操作1成功:", result1);try {const result2 = await operation2();console.log("操作2成功:", result2);} catch (error) {console.error("操作2失败,但继续执行:", error.message);}const result3 = await operation3();console.log("操作3成功:", result3);return "所有操作完成";} catch (error) {console.error("操作失败:", error.message);return "操作链中断";} finally {console.log("清理资源...");}
}performOperations().then(console.log);// 4. 未捕获的 Promise 错误
window.addEventListener("unhandledrejection", (event) => {console.warn("未处理的 Promise 拒绝:", event.promise, event.reason);// 可以阻止默认处理event.preventDefault();
});// 故意不处理错误
Promise.reject(new Error("我没有被处理"));
注意事项:
- 始终在 Promise 链的末尾添加 .catch() 处理错误
- .finally() 用于无论 Promise 成功或失败都需要执行的清理代码
- 不同级别的 try/catch 可以进行细粒度的错误处理
- 使用 unhandledrejection 事件可以捕获全局未处理的 Promise 拒绝
- 调试时可以使用 console.log 或断点来跟踪 Promise 执行流程
总结
JavaScript 内置对象的方法为我们提供了丰富的工具,帮助我们更高效地处理各种编程任务。灵活运用这些方法可以让代码更简洁、更易读,也能提高开发效率。
希望这篇文章能帮助你更好地理解和使用这些常用方法。在实际编程中,建议查阅MDN Web 文档获取更详细的信息和最新的 API 变化。
祝你编程愉快!