TypeScript 类详解:掌握面向对象编程核心(十四)

TypeScript 是一种静态类型的编程语言,广泛应用于现代前端开发。它的类机制是面向对象编程(OOP)的核心,提供了强大的功能,如封装、继承和多态。本文将详细介绍 TypeScript 中类的基本概念、定义、访问控制、继承、方法重写、静态成员、接口实现和抽象类等内容,帮助你更好地理解和使用 TypeScript 类。

类的基本概念

类是面向对象编程中的一个重要概念,它是一种模板或蓝图,用于创建具有相同属性和方法的对象。通过类,我们可以创建多个具有相同结构的对象,这些对象称为类的实例。类封装了数据(属性)和行为(方法),使得代码更加模块化、可复用和易维护。

类的定义

在 TypeScript 中,使用 class 关键字定义类。一个类可以包含以下成员:

  • 字段(Field):类中声明的变量,表示对象的属性。
  • 构造函数(Constructor):类实例化时调用的特殊方法,用于初始化对象。
  • 方法(Method):类中定义的函数,表示对象的行为。

语法格式

class ClassName {
    // 字段声明
    field1: Type;
    field2: Type;

    // 构造函数
    constructor(parameters) {
        // 初始化代码
    }

    // 方法
    methodName(): ReturnType {
        // 方法实现
    }
}

示例:创建简单的类

下面是一个简单的 Person 类的定义:

class Person {
    // 字段
    name: string;
    age: number;

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

    // 方法
    introduce(): void {
        console.log(`我是 ${this.name},今年 ${this.age} 岁`);
    }
}

// 创建类的实例
const person = new Person("Alice", 25);
person.introduce(); // 输出:我是 Alice,今年 25 岁

类的字段和构造函数

类的字段用于存储对象的数据,而构造函数在对象创建时自动调用,用于初始化字段。构造函数的参数可以与字段同名,通过 this 关键字区分。

示例:定义带有字段和构造函数的类

class Car {
    // 字段
    engine: string;

    // 构造函数
    constructor(engine: string) {
        this.engine = engine;
    }

    // 方法
    displayEngine(): void {
        console.log(`发动机型号: ${this.engine}`);
    }
}

// 创建类的实例
const car = new Car("V8 发动机");
console.log(`读取发动机: ${car.engine}`); // 输出:读取发动机: V8 发动机
car.displayEngine(); // 输出:发动机型号: V8 发动机

访问控制修饰符

TypeScript 提供了三种访问修饰符来控制类成员的可访问性:

  • public:公有成员,可以在任何地方访问(默认)。
  • private:私有成员,只能在类内部访问。
  • protected:受保护成员,可以在类内部和子类中访问。

public(默认)

class Person {
    public name: string;
    public age: number;

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

    public introduce(): void {
        console.log(`我是 ${this.name},今年 ${this.age} 岁`);
    }
}

const person = new Person("Alice", 25);
console.log(`姓名: ${person.name}`); // 输出:姓名: Alice
person.introduce(); // 输出:我是 Alice,今年 25 岁

private(私有)

class Person {
    public name: string;
    private secret: string;

    constructor(name: string, secret: string) {
        this.name = name;
        this.secret = secret;
    }

    public revealSecret(): void {
        console.log(`秘密: ${this.secret}`);
    }
}

const person = new Person("Alice", "我喜欢编程");
console.log(`姓名: ${person.name}`); // 输出:姓名: Alice
// console.log(person.secret); // 错误:'secret' 是私有属性
person.revealSecret(); // 输出:秘密: 我喜欢编程

protected(受保护)

class Person {
    protected name: string;

    constructor(name: string) {
        this.name = name;
    }

    protected sayHello(): void {
        console.log(`你好,我是 ${this.name}`);
    }
}

class Student extends Person {
    private grade: string;

    constructor(name: string, grade: string) {

        super(name);
        this.grade = grade;
    }

    public introduce(): void {
        console.log(`我是 ${this.name},年级: ${this.grade}`);
        this.sayHello();
    }
}

const student = new Student("Bob", "高三");
student.introduce(); // 输出:我是 Bob,年级: 高三
// console.log(student.name); // 错误:'name' 是受保护属性

类的继承

继承是面向对象编程中的一个重要特性,允许创建一个类(子类)从另一个类(父类)获取属性和方法。子类可以复用父类的代码,还可以扩展或重写父类的行为。

基本语法

class ChildClass extends ParentClass {
    // 子类新增的属性和方法
}

单继承

// 父类
class Shape {
    area: number;

    constructor(a: number) {
        this.area = a;
    }
}

// 子类
class Circle extends Shape {
    displayArea(): void {
        console.log(`圆的面积: ${this.area}`);
    }
}

const circle = new Circle(223);
circle.displayArea(); // 输出:圆的面积: 223

多层继承

TypeScript 不支持多继承(一个类继承多个类),但支持多层继承(A 继承 B,B 继承 C):

// 根类
class Root {
    str: string;
}

// 子类
class Child extends Root {
}

// 叶子类
class Leaf extends Child {
}

const leaf = new Leaf();
leaf.str = "hello";
console.log(`str 值: ${leaf.str}`); // 输出:str 值: hello

方法重写(Override)

子类可以重写(Override)父类的方法,即在子类中定义与父类同名的方法,实现自己的行为。使用 super 关键字可以调用父类的方法。

// 父类
class PrinterClass {
    doPrint(): void {
        console.log("父类的 doPrint() 方法");
    }
}

// 子类
class StringPrinter extends PrinterClass {
    doPrint(): void {
        super.doPrint(); // 调用父类的方法
        console.log("子类的 doPrint() 方法");
    }
}

const printer = new StringPrinter();
printer.doPrint();
// 输出:
// 父类的 doPrint() 方法
// 子类的 doPrint() 方法

静态成员

使用 static 关键字定义的成员属于类本身,而不是类的实例。可以直接通过类名访问,不需要创建实例。

class StaticMember {
    // 静态属性
    static num: number;

    // 静态方法
    static display(): void {
        console.log(`num 值为 ${StaticMember.num}`);
    }
}

// 直接通过类名访问静态成员
StaticMember.num = 12;
StaticMember.display(); // 输出:num 值为 12

应用场景

静态成员常用于定义类的常量、工具方法或单例模式。

instanceof 运算符

instanceof 用于判断对象是否是某个类的实例。

class Person {
}

const obj = new Person();
const isPerson = obj instanceof Person;
console.log(`obj 是 Person 类的实例吗? ${isPerson}`); // 输出:obj 是 Person 类的实例吗? true

类实现接口

类可以使用 implements 关键字实现接口,确保类符合接口定义的契约。

// 定义接口
interface ILoan {
    interest: number; // 利率
}

// 类实现接口
class AgriLoan implements ILoan {
    interest: number;
    rebate: number; // 回扣

    constructor(interest: number, rebate: number) {
        this.interest = interest;
        this.rebate = rebate;
    }
}

const loan = new AgriLoan(10, 1);
console.log(`利率: ${loan.interest}%,回扣: ${loan.rebate}`); // 输出:利率: 10%,回扣: 1

抽象类

抽象类不能被实例化,只能作为基类供子类继承。抽象类可以包含抽象方法(没有实现的占位方法),子类必须实现这些方法。

// 抽象类
abstract class Animal {
    abstract makeSound(): void; // 抽象方法,子类必须实现

    move(): void {
        console.log("动物在移动");
    }
}

// 具体类
class Dog extends Animal {
    makeSound(): void {
        console.log("汪汪汪!");
    }
}

const dog = new Dog();
dog.move(); // 输出:动物在移动
dog.makeSound(); // 输出:汪汪汪!

综合实例

下面是一个综合运用类的各种特性的示例:

// 接口定义
interface IPrintable {
    print(): void;
}

// 抽象类
abstract class Item {
    protected name: string;
    protected price: number;

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

    abstract getDetails(): string;
}

// 具体类
class Product extends Item implements IPrintable {
    private category: string;

    constructor(name: string, price: number, category: string) {
        super(name, price);
        this.category = category;
    }

    // 实现抽象方法
    getDetails(): string {
        return `产品: ${this.name}, 价格: ¥${this.price}, 类别: ${this.category}`;
    }

    // 实现接口方法
    print(): void {
        console.log(this.getDetails());
    }

    // 静态方法
    static create(name: string, price: number): Product {
        return new Product(name, price, "默认类别");
    }
}

// 使用
const product = Product.create("笔记本电脑", 5999);
product.print(); // 输出:产品: 笔记本电脑, 价格: ¥5999, 类别: 默认类别

// 折扣方法
class DiscountedProduct extends Product {
    private discount: number;

    constructor(name: string, price: number, category: string, discount: number) {
        super(name, price, category);
        this.discount = discount;
    }

    getDetails(): string {
        const discountedPrice = this.price * (1 - this.discount / 100);
        return `产品: ${this.name}, 原价: ¥${this.price}, 折扣: ${this.discount}%, 现价: ¥${discountedPrice.toFixed(2)}`;
    }
}

const discountedProduct = new DiscountedProduct("手机", 2999, "电子产品", 20);
discountedProduct.print(); // 输出:产品: 手机, 原价: ¥2999, 折扣: 20%, 现价: ¥2399.20

总结

TypeScript 的类提供了完整的面向对象编程支持,包括类的定义、访问控制、继承、方法重写、静态成员、接口实现和抽象类等。合理使用类可以使代码更加结构化和可维护。希望本文能帮助你更好地理解和应用 TypeScript 类的相关知识。