第 8 章:类与继承
学习目标
- 用 TS 写类(属性、方法、构造器)
- 学会访问修饰符 public / private / protected
- 掌握继承、抽象类、实现接口
- 理解参数属性、readonly
一、最基本的类
typescript
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `Hi, I'm ${this.name}`;
}
}
const u = new User('Tom', 18);
u.greet(); // "Hi, I'm Tom"二、访问修饰符
typescript
class Account {
public id: string; // 默认 public,外部可访问
private password: string; // 仅本类内部访问
protected email: string; // 本类和子类可访问
readonly createdAt: Date; // 只读,只能赋值一次
constructor(id: string, password: string, email: string) {
this.id = id;
this.password = password;
this.email = email;
this.createdAt = new Date();
}
}
const acc = new Account('1', 'pwd', 'a@b.com');
acc.id; // ✅
acc.password; // ❌ Property 'password' is private
acc.createdAt; // ✅ 可读
acc.createdAt = new Date(); // ❌ Cannot assign⚠️ 坑 1:
private是编译期保护,运行后通过(acc as any).password仍能访问。需要真正私有得用#字段(ES2022)。
三、参数属性(简写)
typescript
class User {
constructor(
public name: string,
private age: number,
readonly id: number,
) {}
greet(): string {
return `${this.name}, ${this.age}岁`;
}
}等价于在构造函数里 this.name = name 这种样板代码。
四、继承(extends)
typescript
class Animal {
constructor(public name: string) {}
move(distance: number): void {
console.log(`${this.name} 移动了 ${distance}m`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // 必须先调 super
}
bark(): void {
console.log('汪汪!');
}
// 重写父类方法
move(distance: number): void {
console.log('跑...');
super.move(distance); // 调父类版本
}
}
const d = new Dog('旺财', '柴犬');
d.move(10); // 跑...\n 旺财 移动了 10m
d.bark(); // 汪汪!⚠️ 坑 2:子类构造函数必须先调
super(),否则this不存在,会报 "super has to be called before accessing this"。
五、抽象类(abstract)
typescript
abstract class Shape {
abstract area(): number; // 抽象方法:不实现,子类必须重写
describe(): void { // 具体方法:可以共用
console.log(`面积:${this.area()}`);
}
}
class Circle extends Shape {
constructor(public r: number) {
super();
}
area(): number {
return Math.PI * this.r ** 2;
}
}
const c = new Circle(5);
c.describe(); // 面积:78.53981633974483
// ❌ 抽象类不能 new
new Shape(); // Cannot create an instance of an abstract class六、实现接口(implements)
typescript
interface Printable {
print(): void;
}
interface Loggable {
log(msg: string): void;
}
class Document implements Printable, Loggable {
constructor(public content: string) {}
print(): void {
console.log(this.content);
}
log(msg: string): void {
console.log(`[LOG] ${msg}`);
}
}⚠️ 坑 3:
implements只检查结构,不改变类的类型。即使实现了接口,类实例也不"等于"接口(强类型语言不一样)。
七、存取器(getter / setter)
typescript
class User {
private _age: number = 0;
get age(): number {
return this._age;
}
set age(value: number) {
if (value < 0) throw new Error('年龄不能为负');
this._age = value;
}
}
const u = new User();
u.age = 18;
console.log(u.age); // 18
u.age = -1; // ❌ Error⚠️ 坑 4:
getter/setter必须配对出现(只读除外),且不能与同名属性冲突。
八、静态成员
typescript
class Counter {
static count: number = 0;
static increment(): void {
Counter.count++;
}
constructor() {
Counter.increment();
}
}
new Counter();
new Counter();
console.log(Counter.count); // 2九、本章小结
| 要点 | 关键 |
|---|---|
| 修饰符 | public(默认)/ private(类内)/ protected(子类) |
| 只读 | readonly,只能赋值一次 |
| 参数属性 | 构造器参数前加修饰符,自动赋值 |
| 继承 | extends + super(),子类必须先 super |
| 抽象类 | abstract class,不能实例化,需子类实现抽象方法 |
| 接口 | implements 检查结构 |
| 静态 | static 属于类,不属于实例 |
动手练习
- 封装:写
BankAccount,balance 用 private,提供deposit/withdraw - 继承:写
Employee extends Person,加salary字段和work()方法 - 抽象类:写
Shape抽象类 +Triangle/Rectangle子类,实现area()
下一章:第 9 章:枚举 →