JavaScript 类(class)(保姆级教程)

JavaScript 类(class):从零开始掌握面向对象编程

在学习 JavaScript 的过程中,你可能已经接触过函数、对象、数组这些基础概念。但当你开始构建更复杂的项目时,会发现代码越来越难维护,变量和逻辑混杂在一起,难以扩展。这时候,“JavaScript 类(class)” 就成了你提升代码结构化的关键工具。

类,就像是一个模板或蓝图,用来创建具有相同属性和方法的对象。它让代码更清晰、更可复用,也更符合现实世界中的“事物”建模方式。比如,你可以定义一个“汽车”类,然后根据这个类生成多辆具体的汽车实例,每辆车都有自己的颜色、速度,但共享相同的驾驶逻辑。

本文将带你一步步理解 JavaScript 类的语法、特性与最佳实践,无论你是初学者还是有一定经验的开发者,都能从中获得实用价值。


类的定义与基本语法

在 ES6(ECMAScript 2015)中,JavaScript 引入了 class 关键字,正式支持面向对象编程。虽然 JavaScript 本身是基于原型的语言,但 class 提供了一种更直观、更接近其他语言(如 Java、C++)的写法。

class Car {
  // 构造函数,用于初始化新实例
  constructor(brand, color) {
    this.brand = brand;  // 实例属性:品牌
    this.color = color;  // 实例属性:颜色
    this.speed = 0;      // 默认速度为 0
  }

  // 实例方法:启动引擎
  startEngine() {
    console.log(`${this.brand} 的引擎已启动!`);
  }

  // 实例方法:加速
  accelerate() {
    this.speed += 10;
    console.log(`当前速度:${this.speed} km/h`);
  }

  // 实例方法:停车
  stop() {
    this.speed = 0;
    console.log(`${this.brand} 已停车。`);
  }
}

重要说明

  • class Car 声明了一个名为 Car 的类。
  • constructor 是类的构造函数,当使用 new 创建实例时自动调用。
  • this 指向当前实例对象,用于访问实例属性和方法。
  • 所有方法都定义在类的原型上,共享使用,节省内存。

创建实例与调用方法

类本身只是一个蓝图,真正要使用它,需要通过 new 关键字创建实例。

// 创建两辆不同的汽车
const myCar = new Car("丰田", "红色");
const yourCar = new Car("本田", "蓝色");

// 调用实例方法
myCar.startEngine();  // 输出:丰田 的引擎已启动!
myCar.accelerate();   // 输出:当前速度:10 km/h
myCar.accelerate();   // 输出:当前速度:20 km/h
myCar.stop();         // 输出:丰田 已停车。

// 每个实例都有独立的状态
console.log(myCar.color);   // 输出:红色
console.log(yourCar.color); // 输出:蓝色

形象比喻
类就像“汽车制造图纸”,而实例就是“实际生产出来的汽车”。你可以根据同一张图纸生产出无数辆不同的车,每辆都有自己的颜色、车牌和行驶记录,但都遵循相同的设计逻辑。


属性与方法的访问控制

JavaScript 类默认没有真正的私有属性,但可以通过命名约定来暗示私有性。ES2022 引入了 # 符号,真正支持私有字段。

class BankAccount {
  // 公共属性
  accountHolder;

  // 私有字段(只能在类内部访问)
  #balance = 0;
  #pin;

  constructor(holder, pin) {
    this.accountHolder = holder;
    this.#pin = pin;
  }

  // 公共方法:存款
  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
      console.log(`存款成功!当前余额:${this.#balance} 元`);
    } else {
      console.log("存款金额必须大于 0");
    }
  }

  // 公共方法:取款
  withdraw(amount, pin) {
    if (pin !== this.#pin) {
      console.log("密码错误!");
      return;
    }

    if (amount > this.#balance) {
      console.log("余额不足!");
      return;
    }

    this.#balance -= amount;
    console.log(`取款成功!当前余额:${this.#balance} 元`);
  }

  // 公共方法:查看余额(只读)
  getBalance() {
    return this.#balance;
  }
}

// 使用示例
const account = new BankAccount("张三", "1234");

account.deposit(1000);     // 存款成功!当前余额:1000 元
account.withdraw(300, "1234"); // 取款成功!当前余额:700 元
console.log(account.getBalance()); // 输出:700
// console.log(account.#balance); // 报错!无法访问私有字段

注意

  • #balance 是私有字段,外部无法直接访问。
  • 私有字段必须在类内部定义和使用。
  • 这种机制增强了封装性,防止数据被意外修改。

继承与扩展:构建类的层次结构

现实世界中,很多事物具有“继承”关系。比如“电动车”是“汽车”的一种。在 JavaScript 中,可以使用 extends 关键字实现继承。

// 父类:汽车
class Car {
  constructor(brand, color) {
    this.brand = brand;
    this.color = color;
    this.speed = 0;
  }

  startEngine() {
    console.log(`${this.brand} 的引擎已启动!`);
  }

  accelerate() {
    this.speed += 10;
    console.log(`当前速度:${this.speed} km/h`);
  }
}

// 子类:电动车(继承 Car)
class ElectricCar extends Car {
  constructor(brand, color, batteryLevel) {
    // 调用父类构造函数
    super(brand, color);
    this.batteryLevel = batteryLevel;  // 新增属性
  }

  // 重写父类方法
  startEngine() {
    console.log(`${this.brand} 的电动马达启动了!`);
    console.log(`电池电量:${this.batteryLevel}%`);
  }

  // 新增方法:充电
  charge(percent) {
    this.batteryLevel += percent;
    if (this.batteryLevel > 100) this.batteryLevel = 100;
    console.log(`充电完成!当前电量:${this.batteryLevel}%`);
  }
}

// 使用
const tesla = new ElectricCar("特斯拉", "白色", 80);
tesla.startEngine();  // 输出:特斯拉 的电动马达启动了!电池电量:80%
tesla.accelerate();   // 输出:当前速度:10 km/h
tesla.charge(20);     // 输出:充电完成!当前电量:100%

关键点

  • extends Car 表示 ElectricCar 继承自 Car
  • super(...) 必须在子类构造函数中第一行调用,用于初始化父类。
  • 子类可以重写父类的方法,实现多态。
  • 子类可以添加新的属性和方法,扩展功能。

静态方法与属性:属于类,而非实例

有时候,我们希望某些方法或属性属于类本身,而不是每个实例。这时就可以使用 static

class MathUtils {
  // 静态方法:计算两个数的最大值
  static max(a, b) {
    return a > b ? a : b;
  }

  // 静态属性:数学常数 π
  static PI = 3.14159265359;

  // 静态方法:判断是否为偶数
  static isEven(num) {
    return num % 2 === 0;
  }
}

// 使用静态方法,无需创建实例
console.log(MathUtils.max(10, 20));      // 输出:20
console.log(MathUtils.PI);               // 输出:3.14159265359
console.log(MathUtils.isEven(8));        // 输出:true

适用场景

  • 工具类方法(如日期格式化、字符串处理)。
  • 常量定义(如 PIE)。
  • 工厂方法(如 Person.createEmployee())。

类的最佳实践与常见误区

在实际开发中,合理使用 JavaScript 类(class) 能极大提升代码质量。以下是一些建议:

建议 说明
避免过度封装 不要为了“类”而类,简单对象可以直接用字面量。
合理使用继承 继承层级不宜过深,优先使用组合(Composition)替代继承。
使用私有字段 尽量用 # 定义私有属性,增强数据安全性。
方法命名清晰 使用动词开头(如 startEnginecalculateTotal),避免模糊命名。
避免在类中写复杂逻辑 保持类职责单一,复杂逻辑应拆分到独立函数或模块。

结语

JavaScript 类(class) 是现代 JavaScript 开发中不可或缺的一部分。它不仅让代码结构更清晰,还提升了可维护性和可扩展性。从创建实例、方法调用,到继承、私有字段、静态成员,每一步都为你构建更健壮的应用打下基础。

无论你是正在学习前端框架(如 Vue 3.0、React 18),还是开发 Node.js 后端服务,理解类的原理和用法,都将让你的代码更加专业、规范。

掌握 JavaScript 类(class),不只是学习语法,更是掌握一种思维方式:将现实世界的问题,抽象为可复用、可扩展的代码模块。这正是编程的魅力所在。