在TypeScript的世界中,类(Class)是面向对象编程(OOP)的核心概念之一,它允许我们创建具有特定属性和方法的对象模板。本章将深入探讨TypeScript中的类继承机制以及成员修饰符的使用,这些特性对于构建可复用、可扩展且易于维护的代码库至关重要。
在面向对象编程中,继承是一种允许我们根据一个已存在的类(称为基类或父类)来创建新类(称为派生类或子类)的机制。子类继承父类的属性和方法,并可以添加新的属性或重写已有的方法,实现功能的扩展或修改。
10.1.1 基本的继承语法
TypeScript中的继承通过extends
关键字实现。以下是一个简单的继承示例:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(): void {
console.log(`${this.name} moves.`);
}
}
class Dog extends Animal {
bark(): void {
console.log(`${this.name} barks.`);
}
}
const myDog = new Dog('Buddy');
myDog.move(); // 输出: Buddy moves.
myDog.bark(); // 输出: Buddy barks.
在上面的例子中,Dog
类通过extends
关键字继承了Animal
类。因此,Dog
类的实例myDog
不仅拥有Dog
类自身定义的bark
方法,还继承了Animal
类的name
属性和move
方法。
10.1.2 构造函数和继承
在子类中,如果你定义了自己的构造函数,则需要通过super()
调用父类的构造函数,以确保父类被正确初始化。super()
可以传递参数给父类的构造函数:
class Dog extends Animal {
constructor(name: string) {
super(name); // 调用父类的构造函数
// 其他初始化代码
}
bark(): void {
console.log(`${this.name} barks.`);
}
}
10.1.3 访问器属性
在TypeScript中,我们还可以使用getter和setter来定义访问器属性,这些属性允许我们对类的私有成员进行封装和控制。访问器属性在继承中尤其有用,因为它们允许子类提供额外的逻辑来处理父类属性的访问:
class Person {
private _age: number;
constructor(age: number) {
this._age = age;
}
get age(): number {
return this._age;
}
set age(value: number) {
if (value < 0) {
throw new Error("Age cannot be negative.");
}
this._age = value;
}
}
class Employee extends Person {
set age(value: number) {
if (value > 65) {
console.log('Employee retirement age set to 65.');
super.age = 65;
} else {
super.age = value;
}
}
}
const emp = new Employee(67);
emp.age = 67; // 输出: Employee retirement age set to 65.
console.log(emp.age); // 输出: 65
在TypeScript中,成员修饰符用于定义类成员的访问级别。主要有三种访问修饰符:public
、protected
、和private
。
10.2.1 public
public
修饰符表示该成员是公开的,可以在类的任何地方、子类以及类的实例中被访问。默认情况下,如果不指定访问修饰符,成员将被视为public
。
10.2.2 private
private
修饰符表示该成员是私有的,只能在定义它的类内部被访问,子类或类的实例都无法访问它。
class Base {
private secret: string = "I'm a secret!";
showSecret(): void {
console.log(this.secret);
}
}
class Derived extends Base {
// 以下尝试访问secret将报错
// showSecretToo(): void {
// console.log(this.secret); // 错误:'secret' 是私有的,只能在类 'Base' 中访问
// }
}
10.2.3 protected
protected
修饰符表示该成员是受保护的,只能在定义它的类及其子类中访问,但无法在类的实例外部访问。
class Base {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Derived extends Base {
sayHello(): void {
console.log(`Hello, my name is ${this.name}.`);
}
}
// 以下尝试访问name将报错
// const base = new Base('Alice');
// console.log(base.name); // 错误:'name' 是受保护的,只能在类 'Base' 及其子类中访问
10.3.1 方法重写(Overriding)
在子类中,我们可以重写从父类继承的方法。这允许我们为继承的方法提供新的实现。
class Animal {
move(): void {
console.log('Animal moves.');
}
}
class Dog extends Animal {
move(): void {
console.log('Dog moves with four legs.');
}
}
10.3.2 super关键字
在子类中,super
关键字可以用于调用父类的构造函数、方法和访问父类的属性。这在进行方法重写时特别有用,允许我们在子类中调用父类方法的原始实现。
class Animal {
constructor(public name: string) {}
move(): void {
console.log(`${this.name} moves.`);
}
}
class Dog extends Animal {
move(): void {
super.move(); // 调用父类的move方法
console.log(`${this.name} barks.`);
}
}
10.3.3 抽象类和抽象方法
TypeScript还支持抽象类和抽象方法。抽象类是一个不能被实例化的类,通常用作基类,为子类提供通用的接口。抽象方法是没有具体实现的方法,必须在子类中实现。
abstract class Animal {
abstract move(): void; // 抽象方法
}
class Dog extends Animal {
move(): void {
console.log('Dog moves.');
}
}
在本章中,我们深入探讨了TypeScript中的类继承机制和成员修饰符的使用。通过继承,我们可以基于已存在的类创建新的类,实现代码的复用和扩展。而成员修饰符则帮助我们控制类成员的访问级别,增强代码的封装性和安全性。此外,我们还讨论了继承中的高级话题,如方法重写、super
关键字的使用、以及抽象类和抽象方法的概念。掌握这些概念,将使你能够更加灵活地运用TypeScript的面向对象特性,编写出更加高效、可维护的代码。