JavaScript作为一门跨平台、多范式的编程语言,已从最初的网页脚本发展为全栈开发的基石。其语言基础可概括为三大核心:语法基础(变量、数据类型、控制流等)、面向对象与原型系统(独特的原型继承机制)、异步编程模型(处理非阻塞操作的核心方案)。掌握这三部分,不仅能写出规范的代码,更能深入理解JavaScript的设计哲学。
本文将系统讲解这三大模块,每个知识点均配备可运行的示例代码和实战场景分析,带你从语法规则到设计思想全面掌握JavaScript语言基础。
语法基础是JavaScript的"骨架",本节简要回顾核心概念,为后续内容铺垫。
JavaScript变量声明有var
/let
/const
三种方式,数据类型分为基本类型(String/Number/Boolean/null/undefined/Symbol/BigInt)和引用类型(Object/Array/Function等)。
// 变量声明(优先const/let)
const PI = 3.14; // 常量,不可重新赋值
let count = 0; // 变量,可重新赋值
// 基本类型(值存储在栈内存)
const name = "Alice"; // String
const age = 25; // Number
const isStudent = true; // Boolean
const id = Symbol("unique"); // Symbol(唯一值)
const bigNum = 9007199254740993n; // BigInt(大整数)
// 引用类型(值存储在堆内存,变量保存引用地址)
const user = { name: "Bob", age: 30 }; // Object
const hobbies = ["reading", "coding"]; // Array
关键区别:基本类型赋值时复制值,引用类型赋值时复制引用地址(修改新变量会影响原变量)。
函数是封装代码的基本单元,ES6+支持箭头函数简化语法;作用域分为全局作用域、函数作用域和块级作用域(let
/const
声明)。
// 函数声明
function add(a, b) {
return a + b;
}
// 箭头函数(简洁语法,词法this绑定)
const multiply = (a, b) => a * b;
// 块级作用域示例
if (true) {
const blockVar = "块级变量";
console.log(blockVar); // 正常访问
}
// console.log(blockVar); // 报错:blockVar is not defined
JavaScript没有传统面向对象的"类"概念(ES6前),而是通过原型链实现继承,这是其与其他语言的核心差异。
对象是JavaScript的核心数据结构,由属性(键值对) 组成,属性值可以是基本类型或函数(方法)。
// 1. 对象字面量(最常用)
const person = {
name: "Alice",
age: 25,
greet() { // 方法简写(ES6+)
return `Hello, ${this.name}`;
}
};
// 2. 构造函数
const car = new Object();
car.brand = "Tesla";
car.model = "Model 3";
// 3. Object.create(基于原型创建)
const animal = { type: "mammal" };
const cat = Object.create(animal); // cat的原型是animal
cat.name = "Tom";
console.log(cat.type); // "mammal"(继承自原型)
// 点表示法(推荐,属性名是合法标识符时)
console.log(person.name); // "Alice"
// 方括号表示法(适合动态属性名或特殊字符)
const prop = "age";
console.log(person[prop]); // 25
// 修改属性
person.age = 26;
person["gender"] = "female"; // 添加新属性
// 删除属性
delete person.gender;
构造函数是用于创建特定类型对象的"模板",通过new
关键字实例化对象;每个构造函数都有一个prototype
属性,实例对象通过__proto__
指向该原型。
// 定义构造函数(首字母大写,约定)
function User(name, age) {
// 实例属性
this.name = name;
this.age = age;
// 实例方法(不推荐:每个实例都会复制一份,浪费内存)
this.sayHi = function() {
console.log(`Hi, ${this.name}`);
};
}
// 原型方法(推荐:所有实例共享,节省内存)
User.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
// 实例化对象
const user1 = new User("Bob", 30);
const user2 = new User("Charlie", 28);
console.log(user1.greet()); // "Hello, I'm Bob"
console.log(user2.greet()); // "Hello, I'm Charlie"
console.log(user1.__proto__ === User.prototype); // true(实例的__proto__指向构造函数的prototype)
__proto__
向上查找原型链,直至找到或到达null
。原型链是JavaScript继承的核心,本质是实例对象通过__proto__
属性串联起来的原型对象链。当访问一个属性时,JavaScript会沿原型链依次查找。
// 构造函数
function Animal(type) {
this.type = type;
}
Animal.prototype.eat = function() {
console.log(`${this.type} is eating`);
};
// 子类构造函数
function Dog(name) {
this.name = name;
this.type = "dog"; // 覆盖父类属性
}
// 核心:设置Dog的原型为Animal实例,实现继承
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog; // 修复constructor指向(可选但推荐)
// 子类原型方法
Dog.prototype.bark = function() {
console.log(`${this.name} is barking`);
};
// 实例化
const dog = new Dog("Buddy");
dog.eat(); // "dog is eating"(继承自Animal原型)
dog.bark(); // "Buddy is barking"(自身原型方法)
// 原型链:dog → Dog.prototype(Animal实例)→ Animal.prototype → Object.prototype → null
dog.bark()
:先查dog
自身属性 → 无 → 查Dog.prototype
→ 找到bark
方法。dog.eat()
:查dog
自身 → 无 → 查Dog.prototype
(Animal实例)→ 无 → 查Animal.prototype
→ 找到eat
方法。dog.toString()
:查dog
自身 → … → 查Object.prototype
→ 找到toString
方法。ES6引入class
语法,简化了原型继承的写法,但本质仍是基于原型链实现。
// 父类
class Animal {
constructor(type) { // 构造方法(对应构造函数)
this.type = type;
}
eat() { // 原型方法(等价于Animal.prototype.eat)
console.log(`${this.type} is eating`);
}
static isAnimal(obj) { // 静态方法(属于类,而非实例)
return obj instanceof Animal;
}
}
// 子类继承(extends关键字)
class Dog extends Animal {
constructor(name) {
super("dog"); // 调用父类构造方法(必须在this前)
this.name = name;
}
bark() { // 子类原型方法
console.log(`${this.name} is barking`);
}
// 重写父类方法
eat() {
super.eat(); // 调用父类方法
console.log(`${this.name} is eating bones`);
}
}
// 使用
const dog = new Dog("Buddy");
dog.eat();
// 输出:
// "dog is eating"(父类方法)
// "Buddy is eating bones"(重写后的方法)
console.log(Animal.isAnimal(dog)); // true(调用静态方法)
class
语法本质是原型的封装,以下等价关系需明确:
class语法 | 原型等价写法 |
---|---|
class A {} |
function A() {} |
constructor() {} |
A.prototype.constructor = function() {} |
method() {} |
A.prototype.method = function() {} |
static staticMethod() {} |
A.staticMethod = function() {} |
extends B |
A.prototype = Object.create(B.prototype) |
// 商品基类
class Product {
constructor(id, name, price) {
this.id = id;
this.name = name;
this.price = price;
}
// 计算折扣价
getDiscountPrice(discount) {
return this.price * (1 - discount);
}
// 显示商品信息
displayInfo() {
return `ID: ${this.id}, 名称: ${this.name}, 价格: ¥${this.price.toFixed(2)}`;
}
}
// 电子产品子类(继承Product)
class ElectronicProduct extends Product {
constructor(id, name, price, brand, warranty) {
super(id, name, price); // 调用父类构造函数
this.brand = brand;
this.warranty = warranty; // 保修期(月)
}
// 重写显示信息方法
displayInfo() {
return `${super.displayInfo()}, 品牌: ${this.brand}, 保修期: ${this.warranty}个月`;
}
// 电子产品特有方法:检查保修状态
checkWarranty(purchaseDate) {
const now = new Date();
const purchase = new Date(purchaseDate);
const monthsUsed = (now - purchase) / (1000 * 60 * 60 * 24 * 30);
return monthsUsed <= this.warranty ? "在保" : "过保";
}
}
// 使用示例
const phone = new ElectronicProduct(1, "智能手机", 4999, "Apple", 12);
console.log(phone.displayInfo());
// 输出:ID: 1, 名称: 智能手机, 价格: ¥4999.00, 品牌: Apple, 保修期: 12个月
console.log("折扣价(9折):", phone.getDiscountPrice(0.1)); // 4499.1
console.log("保修状态:", phone.checkWarranty("2024-01-15")); // 假设当前2024-07-15 → "在保"
JavaScript是单线程语言,通过异步编程实现非阻塞操作,避免长时间任务阻塞主线程(如API请求、文件读取)。
常见异步场景:
setTimeout
/setInterval
)fetch
/XMLHttpRequest
)click
/input
)回调函数是最早的异步解决方案,将异步任务的后续操作定义为函数,作为参数传递给异步API。
// 模拟异步API请求
function fetchData(callback) {
setTimeout(() => { // 模拟网络延迟
const data = { id: 1, name: "异步数据" };
callback(null, data); // 第一个参数为错误,第二个为结果(Node.js回调规范)
}, 1000);
}
// 调用:传入回调函数处理结果
fetchData((error, result) => {
if (error) {
console.error("获取数据失败:", error);
} else {
console.log("获取数据成功:", result); // 1秒后输出:获取数据成功: { id: 1, name: "异步数据" }
}
});
多层嵌套回调会导致代码可读性差、维护困难,称为"回调地狱"(Callback Hell):
// 回调地狱示例(模拟依次获取用户、订单、商品数据)
getUser(userId, (err, user) => {
if (err) { /* 错误处理 */ }
getOrders(user.id, (err, orders) => {
if (err) { /* 错误处理 */ }
getProducts(orders[0].productId, (err, product) => {
if (err) { /* 错误处理 */ }
console.log("商品信息:", product);
});
});
});
Promise是ES6引入的异步解决方案,通过状态管理(pending/fulfilled/rejected)和链式调用解决回调地狱问题。
// 创建Promise对象
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("操作成功"); // 成功时调用resolve,状态变为fulfilled
} else {
reject(new Error("操作失败")); // 失败时调用reject,状态变为rejected
}
}, 1000);
});
// 消费Promise(链式调用)
promise
.then(result => { // 处理成功结果
console.log("成功:", result); // 输出:成功: 操作成功
return result + ",继续处理"; // 传递结果给下一个then
})
.then(nextResult => {
console.log("下一个处理:", nextResult); // 输出:下一个处理: 操作成功,继续处理
})
.catch(error => { // 捕获所有前面的错误
console.error("失败:", error.message);
})
.finally(() => { // 无论成功失败都会执行(清理操作)
console.log("异步操作结束");
});
Promise.all(iterable)
:等待所有Promise成功,返回结果数组;若有一个失败则立即reject。Promise.race(iterable)
:等待第一个完成的Promise(无论成功或失败)。Promise.resolve(value)
:返回一个已成功的Promise。Promise.reject(error)
:返回一个已失败的Promise。// Promise.all示例(并行执行多个异步任务)
const promise1 = Promise.resolve(1);
const promise2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const promise3 = fetch("https://api.example.com/data").then(res => res.json());
Promise.all([promise1, promise2, promise3])
.then(results => console.log("所有结果:", results)) // [1, 2, 接口返回数据]
.catch(error => console.error("有任务失败:", error));
ES2017引入async/await
语法糖,基于Promise实现,允许用同步代码结构编写异步逻辑,进一步简化异步代码。
// 定义async函数(自动返回Promise)
async function fetchData() {
try {
// await等待Promise完成,获取结果
const response = await fetch("https://api.example.com/data"); // 等待网络请求
const data = await response.json(); // 等待JSON解析
return data; // 返回结果会被包装为Promise
} catch (error) {
// 捕获所有异步错误(等价于Promise.catch)
console.error("获取数据失败:", error);
throw error; // 可继续向上抛出
} finally {
console.log("请求结束");
}
}
// 调用async函数(返回Promise)
fetchData()
.then(data => console.log("数据:", data))
.catch(error => console.error("处理失败:", error));
// 并行执行多个异步任务
async function fetchMultipleData() {
const [user, posts] = await Promise.all([
fetch("/api/user").then(res => res.json()),
fetch("/api/posts").then(res => res.json())
]);
console.log("用户:", user);
console.log("文章:", posts);
}
JavaScript单线程通过事件循环实现异步执行,理解事件循环是掌握异步编程的关键。
setTimeout
/setInterval
、I/O
、script
(整体代码)、setImmediate
(Node.js)。Promise.then/catch/finally
、process.nextTick
(Node.js,优先级最高)、queueMicrotask
。示例代码:
console.log("同步代码开始");
setTimeout(() => { // 宏任务
console.log("setTimeout 回调");
}, 0);
Promise.resolve().then(() => { // 微任务
console.log("Promise.then 微任务1");
}).then(() => {
console.log("Promise.then 微任务2");
});
queueMicrotask(() => { // 微任务
console.log("queueMicrotask 微任务");
});
console.log("同步代码结束");
// 输出顺序:
// 同步代码开始
// 同步代码结束
// Promise.then 微任务1
// Promise.then 微任务2
// queueMicrotask 微任务
// setTimeout 回调
// 模拟API请求函数
function fetchUsers() {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 1, name: "Alice", age: 25 },
{ id: 2, name: "Bob", age: 30 }
]);
}, 800);
});
}
function fetchPosts(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 101, title: "JavaScript基础", authorId: userId },
{ id: 102, title: "异步编程实战", authorId: userId }
]);
}, 500);
});
}
// 使用async/await实现异步流程
async function loadAndRenderData() {
try {
// 1. 加载用户列表
const users = await fetchUsers();
console.log("用户列表:", users);
// 2. 加载第一个用户的文章(串行)
const posts = await fetchPosts(users[0].id);
console.log(`${users[0].name}的文章:`, posts);
// 3. 并行加载所有用户的文章(优化性能)
const allPosts = await Promise.all(
users.map(user => fetchPosts(user.id))
);
console.log("所有用户的文章:", allPosts);
// 4. 渲染到页面(简化示例)
const container = document.getElementById("content");
container.innerHTML = `
用户数:
${users.length}
文章总数:
${allPosts.flat().length}
`;
} catch (error) {
console.error("数据加载失败:", error);
document.getElementById("content").innerHTML = "加载失败,请重试
";
}
}
// 执行
loadAndRenderData();
const
/let
)、数据类型(基本/引用类型)、函数(箭头函数)、作用域(块级作用域)。extends
/super
)。Promise.allSettled
/Promise.any
)、取消异步任务(AbortController)。import
/export
)、Proxy/Reflect、BigInt/Symbol应用。useEffect
、Vue的async setup
)。JavaScript的强大之处在于其灵活性,而深入理解语法、原型和异步这三大基础,是写出高效、可维护代码的前提。建议结合实际项目多实践,例如用面向对象思想封装组件,用async/await处理复杂API请求流,逐步提升对JavaScript的掌控力。#### 3.4.2 async/await与Promise的关系
async/await
是Promise的语法糖,以下是等价转换示例:
// Promise链式调用
function getDataPromise() {
return fetchData()
.then(data => processData(data))
.then(result => saveResult(result))
.catch(error => handleError(error));
}
// async/await等价写法
async function getDataAsync() {
try {
const data = await fetchData();
const result = await processData(data);
return await saveResult(result);
} catch (error) {
handleError(error);
}
}
JavaScript是单线程语言,通过事件循环实现非阻塞I/O。理解事件循环是掌握异步编程的关键。
事件循环的核心流程:
setTimeout
、Promise)则交给相应的Web API处理。关键概念:
setTimeout
、setInterval
、I/O
、script
(整体代码)、UI渲染
Promise.then/catch/finally
、async/await
、queueMicrotask
、MutationObserver
console.log("同步代码开始");
// 宏任务
setTimeout(() => {
console.log("setTimeout宏任务1");
// 微任务嵌套在宏任务中
Promise.resolve().then(() => {
console.log("宏任务1中的微任务");
});
}, 0);
// 微任务
Promise.resolve().then(() => {
console.log("Promise微任务1");
// 微任务中嵌套微任务
Promise.resolve().then(() => {
console.log("微任务1中的微任务");
});
});
console.log("同步代码结束");
// 执行顺序:
// 1. 同步代码开始
// 2. 同步代码结束
// 3. Promise微任务1(清空微任务队列)
// 4. 微任务1中的微任务(继续清空微任务队列)
// 5. setTimeout宏任务1(执行一个宏任务)
// 6. 宏任务1中的微任务(清空该宏任务产生的微任务队列)
执行流程图解:
同步代码执行 → 调用栈清空 → 执行所有微任务 → 执行一个宏任务 → 执行该宏任务产生的所有微任务 → ...(循环)
// 封装API请求(基于fetch和async/await)
class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
// 通用请求方法
async request(url, options = {}) {
try {
const response = await fetch(`${this.baseUrl}${url}`, {
headers: {
"Content-Type": "application/json",
...options.headers
},
...options
});
if (!response.ok) {
throw new Error(`HTTP错误:${response.status}`);
}
return await response.json();
} catch (error) {
console.error("请求失败:", error.message);
throw error; // 向上抛出,让调用方处理
}
}
// GET请求
get(url) {
return this.request(url);
}
// POST请求
post(url, data) {
return this.request(url, {
method: "POST",
body: JSON.stringify(data)
});
}
}
// 使用示例:获取用户列表并处理数据
async function getUserData() {
const api = new ApiClient("https://api.example.com");
try {
// 并行请求:同时获取用户和角色数据
const [users, roles] = await Promise.all([
api.get("/users"),
api.get("/roles")
]);
// 处理数据:给用户添加角色名称
const usersWithRoles = users.map(user => {
const role = roles.find(r => r.id === user.roleId);
return {
...user,
roleName: role ? role.name : "未知角色"
};
});
return usersWithRoles;
} catch (error) {
console.error("获取用户数据失败:", error);
return [];
}
}
// 执行
getUserData().then(users => console.log("用户数据:", users));
实现一个用户数据管理系统,功能包括:
class UserManager {
constructor() {
this.api = new ApiClient("https://api.example.com"); // 复用3.6节的ApiClient
this.cache = new Map(); // 缓存用户数据
this.cacheTTL = 5 * 60 * 1000; // 缓存有效期5分钟
}
// 获取用户列表(带缓存)
async getUsers(forceRefresh = false) {
const cacheKey = "users";
const cached = this.cache.get(cacheKey);
// 缓存有效且不强制刷新,直接返回缓存
if (cached && !forceRefresh && Date.now() - cached.timestamp < this.cacheTTL) {
console.log("使用缓存数据");
return cached.data;
}
// 否则请求最新数据
const users = await this.api.get("/users");
this.cache.set(cacheKey, {
data: users,
timestamp: Date.now()
});
return users;
}
// 添加用户
async addUser(userData) {
try {
const newUser = await this.api.post("/users", userData);
// 添加成功后清除缓存,下次获取时刷新
this.cache.delete("users");
return newUser;
} catch (error) {
console.error("添加用户失败:", error);
throw error;
}
}
// 批量获取用户详情(并行请求)
async getUserDetails(userIds) {
if (userIds.length === 0) return [];
// 构建请求数组
const requests = userIds.map(id =>
this.api.get(`/users/${id}`)
);
// 并行执行所有请求
return Promise.all(requests);
}
}
// 使用示例
async function demo() {
const userManager = new UserManager();
try {
// 获取用户列表(首次请求,无缓存)
let users = await userManager.getUsers();
console.log("用户列表:", users);
// 再次获取(使用缓存)
users = await userManager.getUsers();
console.log("再次获取用户列表:", users);
// 添加新用户
const newUser = await userManager.addUser({
name: "新用户",
age: 30,
email: "[email protected]"
});
console.log("新增用户:", newUser);
// 批量获取用户详情
const details = await userManager.getUserDetails([1, 3, 5]);
console.log("用户详情:", details);
} catch (error) {
console.error("操作失败:", error);
}
}
demo();
__proto__
与prototype
的区别?A:prototype
是构造函数的属性,__proto__
是实例对象的属性,指向构造函数的prototype
。
例如:user.__proto__ === User.prototype
→ true
。
A:优先使用class
语法(更简洁、易维护),但需理解其本质仍是原型继承。复杂场景(如多继承)可使用原型链手动实现。
A:未被.catch()
捕获的Promise错误会导致全局错误,可能终止程序执行。在浏览器中会触发window.onerror
,Node.js中会触发unhandledRejection
事件。
async/await
中如何并行执行多个异步任务?A:使用Promise.all()
,而非顺序await
(会导致串行执行,浪费时间):
// 错误(串行执行,总耗时 = t1 + t2)
const data1 = await fetchData1();
const data2 = await fetchData2();
// 正确(并行执行,总耗时 = max(t1, t2))
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
面向对象:
class
语法组织代码,避免深层次原型链继承#
前缀,如#privateField
)异步编程:
.catch()
或try-catch
)Promise.all()
并行执行独立任务async.js
)await
(改用Promise.all()
)性能优化:
本文系统讲解了JavaScript的三大基础模块:
JavaScript的灵活性使其既能处理简单的页面交互,也能构建复杂的大型应用。掌握本文三大核心模块,将为你的JS进阶之路打下坚实基础。记住:理解原理比死记语法更重要,多动手实践才能真正内化知识!
[TOC]### 补充:核心概念可视化表格
访问属性 | 查找路径 | 结果 |
---|---|---|
dog.name |
dog自身 → Dog.prototype → Animal.prototype → Object.prototype | “Buddy”(dog自身属性) |
dog.bark() |
dog自身 → Dog.prototype → Animal.prototype → Object.prototype | 找到bark方法(Dog.prototype) |
dog.eat() |
dog自身 → Dog.prototype → Animal.prototype → Object.prototype | 找到eat方法(Animal.prototype) |
dog.toString() |
dog自身 → … → Object.prototype | 找到toString方法(Object.prototype) |
dog.nonexistent |
dog自身 → … → Object.prototype → null | undefined(未找到) |
任务类型 | 包含API | 执行优先级 | 特点 |
---|---|---|---|
微任务 | Promise.then/catch/finally、async/await、queueMicrotask | 高(调用栈清空后立即执行所有微任务) | 优先级高于宏任务,同一轮事件循环中全部执行完 |
宏任务 | setTimeout、setInterval、I/O、script(整体代码)、UI渲染 | 低(微任务执行完后执行一个) | 每次事件循环仅执行一个,执行后触发新一轮微任务检查 |
使用#
前缀声明私有属性/方法,仅能在类内部访问:
class User {
#password; // 私有字段(外部不可访问)
constructor(name, password) {
this.name = name;
this.#password = password; // 类内部可访问
}
#encrypt() { // 私有方法
return btoa(this.#password); // 简单加密示例
}
verifyPassword(input) {
return this.#encrypt() === btoa(input); // 通过公有方法调用私有方法
}
}
const user = new User("Alice", "123456");
console.log(user.name); // "Alice"(公有属性可访问)
console.log(user.#password); // 报错:Private field '#password' must be declared in an enclosing class
console.log(user.verifyPassword("123456")); // true(通过公有方法验证)
Promise.allSettled
:等待所有Promise完成(无论成功失败),返回包含所有结果的数组。Promise.any
:等待第一个成功的Promise,若所有失败则返回AggregateError。// Promise.allSettled示例(获取所有请求结果,无论成败)
const promises = [
Promise.resolve(1),
Promise.reject(new Error("请求失败")),
Promise.resolve(3)
];
Promise.allSettled(promises).then(results => {
const successful = results
.filter(r => r.status === "fulfilled")
.map(r => r.value);
const failed = results
.filter(r => r.status === "rejected")
.map(r => r.reason.message);
console.log("成功结果:", successful); // [1, 3]
console.log("失败原因:", failed); // ["请求失败"]
});
// Promise.any示例(获取第一个成功的结果)
Promise.any(promises).then(firstSuccess => {
console.log("第一个成功结果:", firstSuccess); // 1(第一个resolve的结果)
});
class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
// 设计思路:通过构造函数注入基础URL,实现API地址统一管理
// 优势:后续更换域名时只需修改一处
}
async request(url, options = {}) {
try {
const response = await fetch(`${this.baseUrl}${url}`, {
headers: {
"Content-Type": "application/json", // 默认JSON格式
...options.headers // 允许覆盖或添加自定义头
},
...options
});
if (!response.ok) {
// 设计思路:将HTTP错误(如404/500)转换为Promise rejection
// 优势:统一错误处理逻辑,避免调用方重复判断response.ok
throw new Error(`HTTP错误:${response.status}`);
}
return await response.json();
} catch (error) {
console.error("请求失败:", error.message);
throw error; // 设计思路:捕获后重新抛出,让调用方决定如何处理
}
}
// ...其余方法
}