JavaScript语言基础全解析:语法、面向对象与异步编程

引言:JavaScript的三大核心支柱

JavaScript作为一门跨平台、多范式的编程语言,已从最初的网页脚本发展为全栈开发的基石。其语言基础可概括为三大核心:语法基础(变量、数据类型、控制流等)、面向对象与原型系统(独特的原型继承机制)、异步编程模型(处理非阻塞操作的核心方案)。掌握这三部分,不仅能写出规范的代码,更能深入理解JavaScript的设计哲学。

本文将系统讲解这三大模块,每个知识点均配备可运行的示例代码实战场景分析,带你从语法规则到设计思想全面掌握JavaScript语言基础。

一、语法基础回顾:构建代码的基石

语法基础是JavaScript的"骨架",本节简要回顾核心概念,为后续内容铺垫。

1.1 变量与数据类型

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

关键区别:基本类型赋值时复制值,引用类型赋值时复制引用地址(修改新变量会影响原变量)。

1.2 函数与作用域

函数是封装代码的基本单元,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的继承范式

JavaScript没有传统面向对象的"类"概念(ES6前),而是通过原型链实现继承,这是其与其他语言的核心差异。

2.1 对象与属性:键值对的集合

对象是JavaScript的核心数据结构,由属性(键值对) 组成,属性值可以是基本类型或函数(方法)。

2.1.1 对象创建方式
// 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"(继承自原型)
2.1.2 属性访问与修改
// 点表示法(推荐,属性名是合法标识符时)
console.log(person.name); // "Alice"

// 方括号表示法(适合动态属性名或特殊字符)
const prop = "age";
console.log(person[prop]); // 25

// 修改属性
person.age = 26;
person["gender"] = "female"; // 添加新属性

// 删除属性
delete person.gender;

2.2 构造函数与原型:对象创建的模板

构造函数是用于创建特定类型对象的"模板",通过new关键字实例化对象;每个构造函数都有一个prototype属性,实例对象通过__proto__指向该原型。

2.2.1 构造函数创建对象
// 定义构造函数(首字母大写,约定)
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)
2.2.2 原型对象的作用
  • 共享方法:原型上的方法被所有实例共享,避免重复创建。
  • 属性查找:访问对象属性时,先查自身属性,若不存在则通过__proto__向上查找原型链,直至找到或到达null

2.3 原型链:继承的实现机制

原型链是JavaScript继承的核心,本质是实例对象通过__proto__属性串联起来的原型对象链。当访问一个属性时,JavaScript会沿原型链依次查找。

2.3.1 原型链结构示例
// 构造函数
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
2.3.2 属性查找流程
  1. 访问dog.bark():先查dog自身属性 → 无 → 查Dog.prototype → 找到bark方法。
  2. 访问dog.eat():查dog自身 → 无 → 查Dog.prototype(Animal实例)→ 无 → 查Animal.prototype → 找到eat方法。
  3. 访问dog.toString():查dog自身 → … → 查Object.prototype → 找到toString方法。

2.4 ES6 class语法:原型的语法糖

ES6引入class语法,简化了原型继承的写法,但本质仍是基于原型链实现。

2.4.1 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(调用静态方法)
2.4.2 class与原型的关系

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)

2.5 实战案例:面向对象的商品管理系统

// 商品基类
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请求、文件读取)。

3.1 异步编程概述:同步vs异步

  • 同步:代码按顺序执行,前一个任务完成后才执行下一个(会阻塞线程)。
  • 异步:任务发起后不等待结果,继续执行后续代码,结果通过回调/通知处理(非阻塞)。

常见异步场景

  • 定时器(setTimeout/setInterval
  • 网络请求(fetch/XMLHttpRequest
  • 文件I/O(Node.js)
  • 事件监听(如click/input

3.2 回调函数:异步的原始实现

回调函数是最早的异步解决方案,将异步任务的后续操作定义为函数,作为参数传递给异步API。

3.2.1 基础回调示例
// 模拟异步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: "异步数据" }
  }
});
3.2.2 回调地狱问题

多层嵌套回调会导致代码可读性差、维护困难,称为"回调地狱"(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);
    });
  });
});

3.3 Promise:异步操作的标准化

Promise是ES6引入的异步解决方案,通过状态管理(pending/fulfilled/rejected)和链式调用解决回调地狱问题。

3.3.1 Promise基础语法
// 创建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("异步操作结束");
  });
3.3.2 Promise常用方法
  • 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));

3.4 async/await:异步的同步写法

ES2017引入async/await语法糖,基于Promise实现,允许用同步代码结构编写异步逻辑,进一步简化异步代码。

3.4.1 基础用法
// 定义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));
3.4.2 并发控制(Promise.all + async/await)
// 并行执行多个异步任务
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);
}

3.5 事件循环(Event Loop):异步执行的核心机制

JavaScript单线程通过事件循环实现异步执行,理解事件循环是掌握异步编程的关键。

3.5.1 执行栈与任务队列
  • 执行栈:存放当前执行的代码(同步任务),遵循"后进先出"原则。
  • 任务队列:存放异步任务的回调函数,分为宏任务微任务
3.5.2 宏任务与微任务
  • 宏任务(Macrotask):包括setTimeout/setIntervalI/Oscript(整体代码)、setImmediate(Node.js)。
  • 微任务(Microtask):包括Promise.then/catch/finallyprocess.nextTick(Node.js,优先级最高)、queueMicrotask
3.5.3 事件循环执行顺序
  1. 执行同步代码(执行栈)。
  2. 执行完同步代码后,检查微任务队列,按顺序执行所有微任务
  3. 微任务执行完毕,执行一个宏任务。
  4. 重复步骤2-3(循环)。

示例代码

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 回调

3.6 实战案例:异步数据加载与渲染

// 模拟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();

四、总结与进阶学习

4.1 核心知识点回顾

  • 语法基础:变量声明(const/let)、数据类型(基本/引用类型)、函数(箭头函数)、作用域(块级作用域)。
  • 面向对象与原型:对象创建(字面量/构造函数/class)、原型链(属性查找与继承)、class语法糖(extends/super)。
  • 异步编程:回调函数(基础但易嵌套)、Promise(链式调用与状态管理)、async/await(同步写法)、事件循环(宏任务/微任务执行顺序)。

4.2 进阶学习方向

  1. 设计模式:单例模式、观察者模式(事件监听本质)、工厂模式等在JavaScript中的应用。
  2. 异步高级特性:Promise并发控制(Promise.allSettled/Promise.any)、取消异步任务(AbortController)。
  3. ES6+新特性:模块化(import/export)、Proxy/Reflect、BigInt/Symbol应用。
  4. 框架与库:React/Vue的异步状态管理(如React Hooks的useEffect、Vue的async setup)。

4.3 推荐资源

  • 官方文档:MDN JavaScript指南

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);
  }
}

3.5 事件循环(Event Loop):异步执行的核心机制

JavaScript是单线程语言,通过事件循环实现非阻塞I/O。理解事件循环是掌握异步编程的关键。

3.5.1 事件循环基本原理

事件循环的核心流程:

  1. 调用栈(Call Stack):执行同步代码,遇到异步任务(如setTimeout、Promise)则交给相应的Web API处理。
  2. 任务队列(Task Queue):异步任务完成后,将回调函数放入任务队列(分为宏任务队列微任务队列)。
  3. 事件循环:当调用栈为空时,优先清空微任务队列(按顺序执行所有微任务),然后执行一个宏任务,重复此过程。

关键概念

  • 宏任务(Macrotask)setTimeoutsetIntervalI/Oscript(整体代码)、UI渲染
  • 微任务(Microtask)Promise.then/catch/finallyasync/awaitqueueMicrotaskMutationObserver
3.5.2 执行顺序示例
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中的微任务(清空该宏任务产生的微任务队列)

执行流程图解

同步代码执行 → 调用栈清空 → 执行所有微任务 → 执行一个宏任务 → 执行该宏任务产生的所有微任务 → ...(循环)

3.6 异步编程实战:API请求与数据处理

// 封装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));

四、综合实战:面向对象的异步数据管理系统

4.1 需求描述

实现一个用户数据管理系统,功能包括:

  • 使用class封装数据请求与处理
  • 支持用户列表查询、添加、删除操作
  • 异步操作使用async/await处理
  • 实现简单的缓存机制避免重复请求

4.2 实现代码

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();

五、常见问题与最佳实践

5.1 原型链与继承常见问题

Q1:__proto__prototype的区别?

Aprototype是构造函数的属性,__proto__是实例对象的属性,指向构造函数的prototype
例如:user.__proto__ === User.prototypetrue

Q2:class继承与原型继承的选择?

A:优先使用class语法(更简洁、易维护),但需理解其本质仍是原型继承。复杂场景(如多继承)可使用原型链手动实现。

5.2 异步编程常见陷阱

Q1:Promise未捕获的错误会导致什么问题?

A:未被.catch()捕获的Promise错误会导致全局错误,可能终止程序执行。在浏览器中会触发window.onerror,Node.js中会触发unhandledRejection事件。

Q2: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()]);

5.3 最佳实践总结

  1. 面向对象

    • 使用class语法组织代码,避免深层次原型链继承
    • 优先组合(Composition)而非继承(Inheritance)
    • 封装私有属性(ES2022+可用#前缀,如#privateField
  2. 异步编程

    • 始终处理Promise错误(.catch()try-catch
    • 使用Promise.all()并行执行独立任务
    • 复杂异步流程考虑使用异步库(如async.js
    • 避免在循环中使用await(改用Promise.all()
  3. 性能优化

    • 减少原型链查找层级(避免过深继承)
    • 使用事件委托优化事件监听
    • 合理使用缓存减少重复异步请求

六、总结与进阶学习

6.1 核心知识点回顾

本文系统讲解了JavaScript的三大基础模块:

  • 语法基础:变量类型、函数作用域(简要回顾)
  • 面向对象与原型:原型链、构造函数、class继承、实战案例
  • 异步编程:回调函数、Promise、async/await、事件循环机制

6.2 进阶学习路径

  1. 深入底层:V8引擎工作原理、JavaScript执行上下文
  2. 设计模式:工厂模式、单例模式、观察者模式等在JS中的应用
  3. 异步高级:Generator函数、AbortController取消异步任务
  4. TypeScript:添加类型系统,提升代码健壮性
  5. 框架源码:学习React/Vue等框架中面向对象和异步编程的应用

6.3 推荐资源

  • 书籍:《你不知道的JavaScript》(上中下卷)、《JavaScript设计模式与开发实践》
  • 文档:[MDN Web Docs - JavaScript]

JavaScript的灵活性使其既能处理简单的页面交互,也能构建复杂的大型应用。掌握本文三大核心模块,将为你的JS进阶之路打下坚实基础。记住:理解原理比死记语法更重要,多动手实践才能真正内化知识!

目录导航

[TOC]### 补充:核心概念可视化表格

表1:原型链查找路径示例(基于2.3.1节Dog实例)
访问属性 查找路径 结果
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(未找到)
表2:宏任务与微任务分类及执行优先级
任务类型 包含API 执行优先级 特点
微任务 Promise.then/catch/finally、async/await、queueMicrotask 高(调用栈清空后立即执行所有微任务) 优先级高于宏任务,同一轮事件循环中全部执行完
宏任务 setTimeout、setInterval、I/O、script(整体代码)、UI渲染 低(微任务执行完后执行一个) 每次事件循环仅执行一个,执行后触发新一轮微任务检查

补充:ES6+面向对象高级特性

私有字段与方法(ES2022+)

使用#前缀声明私有属性/方法,仅能在类内部访问:

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.any(ES2020+)
  • 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的结果)
});

代码注释补充:ApiClient类设计思路

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; // 设计思路:捕获后重新抛出,让调用方决定如何处理
    }
  }
  // ...其余方法
}

你可能感兴趣的:(前端系列,javascript,udp,开发语言)