TypeScript 类(Class)完全指南

157 阅读4分钟

TypeScript 类(Class)完全指南

目录

  1. 基本概念
  2. 类的成员
  3. 继承
  4. 访问修饰符
  5. 抽象类
  6. 高级特性
  7. 最佳实践

基本概念

类的定义

class Person {
  // 属性声明
  name: string;
  age: number;

  // 构造函数
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  // 方法
  sayHello(): void {
    console.log(`Hello, I'm ${this.name}`);
  }
}

// 使用类
const person = new Person("John", 30);
person.sayHello();  // 输出: Hello, I'm John

属性简写

// 使用访问修饰符可以自动创建并初始化属性
class Person {
  constructor(
    public name: string,
    private age: number,
    protected email: string
  ) {}
}

// 等同于
class Person {
  public name: string;
  private age: number;
  protected email: string;

  constructor(name: string, age: number, email: string) {
    this.name = name;
    this.age = age;
    this.email = email;
  }
}

类的定义解释

什么是类?

类(Class)是一个用于创建对象的模板,它封装了数据和操作数据的方法。类是面向对象编程的基础构建块。

类的组成部分:

  1. 构造函数(Constructor)
  • 用于初始化类的新实例
  • 在创建对象时自动调用
  • 可以接收参数来设置初始状态
class Person {
  name: string;
  age: number;

  // 构造函数
  constructor(name: string, age: number) {
    // 初始化实例属性
    this.name = name;
    this.age = age;
  }
}
  1. 属性(Properties)
  • 类的数据成员
  • 可以是实例属性或静态属性
  • 可以有访问修饰符
class Example {
  // 实例属性
  public name: string;          // 公共属性
  private age: number;          // 私有属性
  protected email: string;      // 受保护属性
  readonly id: string;          // 只读属性
  static count: number = 0;     // 静态属性
  optional?: string;            // 可选属性
}
  1. 方法(Methods)
  • 类的行为
  • 可以访问和修改类的属性
  • 可以是实例方法或静态方法
class Calculator {
  // 实例方法
  add(a: number, b: number): number {
    return a + b;
  }

  // 静态方法
  static multiply(a: number, b: number): number {
    return a * b;
  }
}
  1. 访问器(Accessors)
  • getter 和 setter 方法
  • 用于控制属性的访问和修改
class Person {
  private _age: number = 0;

  // getter
  get age(): number {
    return this._age;
  }

  // setter
  set age(value: number) {
    if (value >= 0 && value <= 120) {
      this._age = value;
    }
  }
}

类的特性:

  1. 封装(Encapsulation)
  • 将数据和方法捆绑在一起
  • 通过访问修饰符控制访问权限
class BankAccount {
  private balance: number = 0;

  deposit(amount: number): void {
    if (amount > 0) {
      this.balance += amount;
    }
  }

  getBalance(): number {
    return this.balance;
  }
}
  1. 继承(Inheritance)
  • 允许类继承另一个类的特性
  • 支持代码重用
class Animal {
  protected name: string;
  
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark(): void {
    console.log(`${this.name} says woof!`);
  }
}
  1. 多态(Polymorphism)
  • 允许使用父类类型引用子类对象
  • 支持方法重写
class Shape {
  area(): number {
    return 0;
  }
}

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }

  override area(): number {
    return Math.PI * this.radius ** 2;
  }
}

class Square extends Shape {
  constructor(private side: number) {
    super();
  }

  override area(): number {
    return this.side ** 2;
  }
}

// 多态使用
const shapes: Shape[] = [
  new Circle(5),
  new Square(4)
];

shapes.forEach(shape => {
  console.log(shape.area());  // 调用各自的实现
});

类的成员

1. 实例属性

class Car {
  // 实例属性
  brand: string;
  model: string;
  year: number = 2023;  // 可以设置默认值
  
  // 可选属性
  color?: string;

  // 只读属性
  readonly vin: string;

  constructor(brand: string, model: string, vin: string) {
    this.brand = brand;
    this.model = model;
    this.vin = vin;
  }
}

2. 静态成员

class MathUtils {
  // 静态属性
  static PI: number = 3.14159;

  // 静态方法
  static square(x: number): number {
    return x * x;
  }

  // 静态块(ES2022+)
  static {
    // 初始化静态成员
    this.PI = Math.PI;
  }
}

console.log(MathUtils.PI);      // 3.14159
console.log(MathUtils.square(4)); // 16

3. 访问器

class Employee {
  private _salary: number = 0;

  // getter
  get salary(): number {
    return this._salary;
  }

  // setter
  set salary(value: number) {
    if (value >= 0) {
      this._salary = value;
    }
  }
}

const emp = new Employee();
emp.salary = 5000;  // 使用 setter
console.log(emp.salary);  // 使用 getter,输出: 5000

继承

基本继承

class Animal {
  constructor(protected name: string) {}

  move(distance: number = 0): void {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);  // 调用父类构造函数
  }

  // 重写父类方法
  move(distance: number = 5): void {
    console.log("Running...");
    super.move(distance);  // 调用父类方法
  }

  // 新增方法
  bark(): void {
    console.log("Woof! Woof!");
  }
}

方法重写

class Shape {
  getArea(): number {
    return 0;
  }
}

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }

  // 重写 getArea 方法
  override getArea(): number {  // 使用 override 关键字
    return Math.PI * this.radius ** 2;
  }
}

访问修饰符

1. public(默认)

class Example {
  public name: string;  // 可以在任何地方访问
}

2. private

class Example {
  private secretKey: string;  // 只能在类内部访问

  private generateKey(): string {
    return Math.random().toString(36);
  }
}

3. protected

class Parent {
  protected data: string;  // 可以在子类中访问
}

class Child extends Parent {
  showData() {
    console.log(this.data);  // OK
  }
}

4. readonly

class Config {
  readonly API_KEY: string;
  
  constructor(key: string) {
    this.API_KEY = key;  // 只能在构造函数中赋值
  }
}

抽象类

基本用法

abstract class Vehicle {
  constructor(protected brand: string) {}

  // 抽象方法必须在子类中实现
  abstract start(): void;

  // 具体方法可以包含实现
  stop(): void {
    console.log("Vehicle stopped");
  }
}

class Car extends Vehicle {
  // 必须实现抽象方法
  start(): void {
    console.log(`${this.brand} car starting...`);
  }
}

何时使用抽象类

  1. 需要定义一个基类,但基类本身不应该被实例化
  2. 有一些通用的实现,但部分行为需要子类特定实现
  3. 强制子类实现某些方法
// 示例:支付系统
abstract class PaymentProcessor {
  constructor(protected amount: number) {}

  // 通用的支付流程
  process(): void {
    this.validate();
    this.doPayment();
    this.sendReceipt();
  }

  // 具体实现
  protected sendReceipt(): void {
    console.log("Receipt sent");
  }

  // 抽象方法 - 不同支付方式有不同的验证逻辑
  protected abstract validate(): void;

  // 抽象方法 - 不同支付方式有不同的支付逻辑
  protected abstract doPayment(): void;
}

// 信用卡支付实现
class CreditCardProcessor extends PaymentProcessor {
  constructor(
    amount: number,
    private cardNumber: string,
    private cvv: string
  ) {
    super(amount);
  }

  protected validate(): void {
    // 验证信用卡信息
  }

  protected doPayment(): void {
    // 处理信用卡支付
  }
}

高级特性

1. 接口实现

interface Printable {
  print(): void;
}

interface Serializable {
  serialize(): string;
}

// 类可以实现多个接口
class Document implements Printable, Serializable {
  print(): void {
    // 实现打印功能
  }

  serialize(): string {
    // 实现序列化功能
    return "";
  }
}

2. 泛型类

class Container<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

const numberContainer = new Container<number>(123);
const stringContainer = new Container<string>("hello");

最佳实践

1. 封装

class BankAccount {
  private balance: number = 0;

  deposit(amount: number): void {
    if (amount > 0) {
      this.balance += amount;
    }
  }

  getBalance(): number {
    return this.balance;
  }
}

2. 组合优于继承

// 不好的做法:过度继承
class Animal {}
class FlyingAnimal extends Animal {}
class SwimmingAnimal extends Animal {}
class FlyingSwimmingAnimal extends FlyingAnimal {}

// 好的做法:组合
interface Flyer {
  fly(): void;
}

interface Swimmer {
  swim(): void;
}

class Duck implements Flyer, Swimmer {
  fly(): void {
    // 实现飞行
  }

  swim(): void {
    // 实现游泳
  }
}

3. 单一职责原则

// 不好的做法
class UserManager {
  saveUser() { /* ... */ }
  validateEmail() { /* ... */ }
  sendEmail() { /* ... */ }
}

// 好的做法
class UserRepository {
  saveUser() { /* ... */ }
}

class EmailValidator {
  validate(email: string) { /* ... */ }
}

class EmailService {
  send(to: string, content: string) { /* ... */ }
}

总结

  1. 类的核心概念:

    • 属性和方法封装
    • 继承和多态
    • 访问控制
    • 抽象和实现
  2. 最佳实践:

    • 使用适当的访问修饰符
    • 优先使用组合而不是继承
    • 遵循单一职责原则
    • 使用抽象类定义契约
  3. 使用场景:

    • 面向对象编程
    • 代码复用
    • 框架开发
    • 大型应用架构