类是面向对象编程的核心概念。TypeScript 扩展了 JavaScript 的类,添加了类型注解、访问修饰符、抽象类等特性。本章将深入讲解 TypeScript 类的完整功能。
```typescript class Person {
// 属性声明
name: string;
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 方法
greet(): string {
return `Hello, my name is ${this.name}`;
}
// 获取年龄
getAge(): number {
return this.age;
}
}
创建实例 const alice = new Person(“Alice”, 25); console.log(alice.greet()); “Hello, my name is Alice” ```
```typescript 使用 public 修饰符简化属性声明 class Person2 { constructor( public name: string, public age: number, private id: string ) {} greet(): string { return `Hello, my name is ${this.name}`; } } const bob = new Person2(“Bob”, 30, “user-123”); console.log(bob.name); “Bob” console.log(bob.id); Error: 私有属性 ```
```typescript class Animal {
public name: string; // 默认就是 public
constructor(name: string) {
this.name = name;
}
public move(distance: number): void {
console.log(`${this.name} moved ${distance}m`);
}
}
const dog = new Animal(“Dog”); console.log(dog.name); OK dog.move(10); OK ```
```typescript class BankAccount {
private balance: number = 0;
private readonly accountId: string;
constructor(accountId: string, initialBalance: number) {
this.accountId = accountId;
this.balance = initialBalance;
}
deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
}
}
withdraw(amount: number): boolean {
if (amount > 0 && this.balance >= amount) {
this.balance -= amount;
return true;
}
return false;
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount(“ACC-001”, 1000); account.deposit(500); console.log(account.getBalance()); 1500 console.log(account.balance); Error: 私有属性 account.balance = 1000000; Error ``` ==== 6.2.3 protected ==== ```typescript class Vehicle { protected brand: string; protected speed: number = 0; constructor(brand: string) { this.brand = brand; } protected accelerate(amount: number): void { this.speed += amount; } getSpeed(): number { return this.speed; } } class Car extends Vehicle { private model: string; constructor(brand: string, model: string) { super(brand); this.model = model; } speedUp(): void { 可以访问父类的 protected 成员
this.accelerate(10);
console.log(`${this.brand} ${this.model} speeding up to ${this.speed}km/h`);
}
}
const car = new Car(“Toyota”, “Camry”); car.speedUp(); OK car.accelerate(20); Error: 受保护的方法 car.brand; Error: 受保护的属性 ``` ==== 6.2.4 readonly ==== ```typescript class Employee { readonly id: string; name: string; readonly hireDate: Date; constructor(id: string, name: string) { this.id = id; this.name = name; this.hireDate = new Date(); } 不能在方法中修改 readonly 属性
// updateId(newId: string): void {
// this.id = newId; // Error
// }
}
const emp = new Employee(“E001”, “Alice”); console.log(emp.id); emp.id = “E002”; Error ```
```typescript class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
move(distance: number = 0): void {
console.log(`${this.name} moved ${distance}m`);
}
makeSound(): void {
console.log("Some sound");
}
}
class Dog extends Animal {
private breed: string;
constructor(name: string, breed: string) {
super(name); // 必须调用父类构造函数
this.breed = breed;
}
// 重写方法
makeSound(): void {
console.log("Woof! Woof!");
}
fetch(): void {
console.log(`${this.name} is fetching the ball`);
}
getBreed(): string {
return this.breed;
}
}
const dog = new Dog(“Buddy”, “Golden Retriever”); dog.move(10); 继承的方法 dog.makeSound(); 重写的方法 dog.fetch(); 子类的方法 ``` ==== 6.3.2 super 关键字 ==== ```typescript class Rectangle { constructor( protected width: number, protected height: number ) {} getArea(): number { return this.width * this.height; } describe(): string { return `Rectangle: ${this.width}x${this.height}`; } } class Square extends Rectangle { constructor(side: number) { super(side, side); 调用父类构造函数
}
describe(): string {
// 调用父类方法
const baseDescription = super.describe();
return `${baseDescription} (Square)`;
}
}
const square = new Square(5); console.log(square.getArea()); 25 console.log(square.describe()); “Rectangle: 5×5 (Square)” ```
```typescript class Person {
constructor(protected name: string) {}
introduce(): string {
return `I am ${this.name}`;
}
}
class Student extends Person {
constructor(
name: string,
private grade: number
) {
super(name);
}
// 方法重写
introduce(): string {
const base = super.introduce();
return `${base}, a student in grade ${this.grade}`;
}
}
方法重载 class Calculator { add(a: number, b: number): number; add(a: string, b: string): string; add(a: any, b: any): any { if (typeof a === “number” && typeof b === “number”) { return a + b; } return String(a) + String(b); } } const calc = new Calculator(); console.log(calc.add(1, 2)); 3 console.log(calc.add(“a”, “b”)); “ab” ``` ===== 6.4 抽象类 ===== ==== 6.4.1 abstract 关键字 ==== ```typescript 抽象类不能实例化 abstract class Shape {
protected color: string;
constructor(color: string) {
this.color = color;
}
// 抽象方法必须在子类中实现
abstract getArea(): number;
abstract getPerimeter(): number;
// 普通方法
describe(): string {
return `A ${this.color} shape`;
}
}
具体类必须实现所有抽象方法 class Circle extends Shape { constructor( color: string, private radius: number ) { super(color); } getArea(): number { return Math.PI * this.radius 2; } getPerimeter(): number { return 2 * Math.PI * this.radius; } } class Rectangle extends Shape { constructor( color: string, private width: number, private height: number ) { super(color); } getArea(): number { return this.width * this.height; } getPerimeter(): number { return 2 * (this.width + this.height); } } 使用 const shapes: Shape[] = [ new Circle(“red”, 5), new Rectangle(“blue”, 4, 6) ]; shapes.forEach(shape ⇒ { console.log(`${shape.describe()}: Area=${shape.getArea().toFixed(2)}`); }); 抽象类不能实例化 const shape = new Shape(“green”); Error ``` ===== 6.5 存取器(Getters 和 Setters) ===== ==== 6.5.1 基本使用 ==== ```typescript class Employee { private _name: string; private _salary: number; constructor(name: string, salary: number) { this._name = name; this._salary = salary; } getter get name(): string { return this._name; } setter set name(value: string) { if (value.length < 2) { throw new Error(“Name must be at least 2 characters”); } this._name = value; } get salary(): number { return this._salary; } 只读属性(只有 getter) get annualSalary(): number { return this._salary * 12; } } const emp = new Employee(“Alice”, 5000); console.log(emp.name); “Alice” emp.name = “Bob”; 使用 setter console.log(emp.annualSalary); 60000 emp.salary = 6000; Error: 没有 setter ``` ==== 6.5.2 计算属性 ==== ```typescript class Temperature { private _celsius: number; constructor(celsius: number) { this._celsius = celsius; } get celsius(): number { return this._celsius; } set celsius(value: number) { this._celsius = value; } get fahrenheit(): number { return (this._celsius * 9 / 5) + 32; } set fahrenheit(value: number) { this._celsius = (value - 32) * 5 / 9; } get kelvin(): number { return this._celsius + 273.15; } } const temp = new Temperature(25); console.log(temp.fahrenheit); 77 console.log(temp.kelvin); 298.15 temp.fahrenheit = 100; console.log(temp.celsius); 37.777… ``` ===== 6.6 静态成员 ===== ==== 6.6.1 静态属性和方法 ==== ```typescript class MathUtils { 静态属性 static readonly PI: number = 3.14159; static readonly E: number = 2.71828; 静态方法 static circleArea(radius: number): number { return this.PI * radius * radius; } static max(a: number, b: number): number { return a > b ? a : b; } 静态工厂方法 static createRandom(): number { return Math.random(); } } 无需实例化即可使用 console.log(MathUtils.PI); console.log(MathUtils.circleArea(5)); console.log(MathUtils.max(10, 20)); 不能通过实例访问 const utils = new MathUtils(); utils.PI; Error ``` ==== 6.6.2 单例模式 ==== ```typescript class Database { private static instance: Database; private connection: string; private constructor(connectionString: string) { this.connection = connectionString; } static getInstance(connectionString: string): Database { if (!Database.instance) { Database.instance = new Database(connectionString); } return Database.instance; } query(sql: string): any { console.log(`Executing: ${sql}`); return []; } } 使用 const db1 = Database.getInstance(“mysql:localhost”); const db2 = Database.getInstance(“mysql:remote”); 返回同一个实例 console.log(db1 === db2); true ``` ===== 6.7 类与接口 ===== ==== 6.7.1 类实现接口 ==== ```typescript interface Printable { print(): void; } interface Loggable { log(): void; } 类可以实现多个接口 class Document implements Printable, Loggable { constructor(private content: string) {} print(): void { console.log(“Printing:”, this.content); } log(): void { console.log(“Logging document content”); } } ``` ==== 6.7.2 接口继承类 ==== ```typescript class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } } 接口继承类 interface Point3D extends Point { z: number; } const point3d: Point3D = { x: 1, y: 2, z: 3 }; ``` ===== 6.8 高级类特性 ===== ==== 6.8.1 泛型类 ==== ```typescript class GenericStack<T> { private items: T[] = []; push(item: T): void { this.items.push(item); } pop(): T | undefined { return this.items.pop(); } peek(): T | undefined { return this.items[this.items.length - 1]; } isEmpty(): boolean { return this.items.length === 0; } size(): number { return this.items.length; } } 使用 const numberStack = new GenericStack<number>(); numberStack.push(1); numberStack.push(2); console.log(numberStack.pop()); 2 const stringStack = new GenericStack<string>(); stringStack.push(“hello”); stringStack.push(“world”); console.log(stringStack.pop()); “world” ``` ==== 6.8.2 抽象属性 ==== ```typescript abstract class Component { abstract id: string; 抽象属性 abstract render(): void; mount(): void { console.log(`Mounting component ${this.id}`); this.render(); } } class ButtonComponent extends Component { id: string = “button-” + Math.random().toString(36); render(): void { console.log(“Rendering button”); } } ``` ===== 6.9 本章小结 ===== 本章我们学习了: 1. 类基础 - 属性声明、构造函数、方法 2. 访问修饰符 - public、private、protected、readonly 3. 继承 - extends、super、方法重写 4. 抽象类 - abstract、抽象方法 5. 存取器 - getter 和 setter 6. 静态成员 - 静态属性、静态方法、单例模式 7. 类与接口 - 类实现接口、接口继承类 8. 泛型类 - 类型参数化 ===== 6.10 练习题 ===== ==== 练习 1:实现银行账户类 ==== 设计一个 BankAccount 类,要求: - 私有属性:balance(余额)、accountNumber(账号)、ownerName(所有者) - 公共方法:deposit(存款)、withdraw(取款)、getBalance(查询余额) - 取款时检查余额是否充足 - 使用 getter 获取账户信息 <details> <summary>参考答案</summary> ```typescript class BankAccount { private _balance: number = 0; private readonly _accountNumber: string; private readonly _ownerName: string; private _transactionHistory: string[] = []; constructor(accountNumber: string, ownerName: string, initialBalance: number = 0) { this._accountNumber = accountNumber; this._ownerName = ownerName; this._balance = initialBalance; this._logTransaction(“ACCOUNT_OPENED”, initialBalance); } get accountNumber(): string { return this._accountNumber; } get ownerName(): string { return this._ownerName; } get balance(): number { return this._balance; } get transactionHistory(): readonly string[] { return […this._transactionHistory]; } deposit(amount: number): void { if (amount ⇐ 0) { throw new Error(“Deposit amount must be positive”); } this._balance += amount; this._logTransaction(“DEPOSIT”, amount); } withdraw(amount: number): void { if (amount ⇐ 0) { throw new Error(“Withdrawal amount must be positive”); } if (amount > this._balance) { throw new Error(“Insufficient funds”); } this._balance -= amount; this._logTransaction(“WITHDRAWAL”, amount); } transfer(amount: number, targetAccount: BankAccount): void { this.withdraw(amount); targetAccount.deposit(amount); this._logTransaction(`TRANSFER_TO_${targetAccount.accountNumber}`, amount); } private _logTransaction(type: string, amount: number): void { const timestamp = new Date().toISOString(); this._transactionHistory.push( `[${timestamp}] ${type}: $${amount.toFixed(2)}, Balance: $${this._balance.toFixed(2)}` ); } } 使用 const account1 = new BankAccount(“ACC-001”, “Alice”, 1000); const account2 = new BankAccount(“ACC-002”, “Bob”, 500); account1.deposit(500); account1.transfer(200, account2); console.log(account1.balance); 1300 console.log(account2.balance); 700 console.log(account1.transactionHistory); ``` </details> ==== 练习 2:实现图形类层次结构 ==== 设计一个图形类系统,要求: - 抽象基类 Shape,包含 color 属性和抽象方法 getArea()、getPerimeter() - 具体类:Circle、Rectangle、Triangle - 每个类有自己的属性(radius、width/height、sides) - 实现静态工厂方法 <details> <summary>参考答案</summary> ```typescript abstract class Shape { constructor(protected color: string) {} abstract getArea(): number; abstract getPerimeter(): number; abstract describe(): string; getColor(): string { return this.color; } setColor(color: string): void { this.color = color; } } class Circle extends Shape { constructor(color: string, private radius: number) { super(color); if (radius ⇐ 0) { throw new Error(“Radius must be positive”); } } getArea(): number { return Math.PI * this.radius ** 2; } getPerimeter(): number { return 2 * Math.PI * this.radius; } describe(): string { return `Circle(${this.radius}) - ${this.color}`; } getRadius(): number { return this.radius; } setRadius(radius: number): void { if (radius ⇐ 0) { throw new Error(“Radius must be positive”); } this.radius = radius; } } class Rectangle extends Shape { constructor( color: string, private width: number, private height: number ) { super(color); if (width ⇐ 0 || height ⇐ 0) { throw new Error(“Dimensions must be positive”); } } getArea(): number { return this.width * this.height; } getPerimeter(): number { return 2 * (this.width + this.height); } describe(): string { return `Rectangle(${this.width}x${this.height}) - ${this.color}`; } isSquare(): boolean { return this.width === this.height; } } class Triangle extends Shape { constructor( color: string, private a: number, private b: number, private c: number ) { super(color); 验证三角形不等式 if (a + b ⇐ c || a + c ⇐ b || b + c ⇐ a) { throw new Error(“Invalid triangle sides”); } } getArea(): number { 海伦公式 const s = this.getPerimeter() / 2; return Math.sqrt(s * (s - this.a) * (s - this.b) * (s - this.c)); } getPerimeter(): number { return this.a + this.b + this.c; } describe(): string { return `Triangle(${this.a}, ${this.b}, ${this.c}) - ${this.color}`; } } 形状工厂 class ShapeFactory { static createCircle(color: string, radius: number): Circle { return new Circle(color, radius); } static createRectangle(color: string, width: number, height: number): Rectangle { return new Rectangle(color, width, height); } static createTriangle(color: string, a: number, b: number, c: number): Triangle { return new Triangle(color, a, b, c); } static createRandomShape(): Shape { const shapes = [“circle”, “rectangle”, “triangle”]; const randomShape = shapes[Math.floor(Math.random() * shapes.length)]; const color = [“red”, “blue”, “green”][Math.floor(Math.random() * 3)]; switch (randomShape) { case “circle”: return new Circle(color, Math.random() * 10 + 1); case “rectangle”: return new Rectangle(color, Math.random() * 10 + 1, Math.random() * 10 + 1); case “triangle”: return new Triangle(color, 3, 4, 5); default: throw new Error(“Unknown shape”); } } } 使用 const shapes: Shape[] = [ ShapeFactory.createCircle(“red”, 5), ShapeFactory.createRectangle(“blue”, 4, 6), ShapeFactory.createTriangle(“green”, 3, 4, 5) ]; shapes.forEach(shape ⇒ { console.log(`${shape.describe()}`); console.log(` Area: ${shape.getArea().toFixed(2)}`); console.log(` Perimeter: ${shape.getPerimeter().toFixed(2)}`); }); ``` </details> ==== 练习 3:实现泛型集合类 ==== 实现一个泛型的 Collection 类,要求: - 支持添加、删除、查询元素 - 支持过滤、映射、归约操作 - 支持迭代器 <details> <summary>参考答案</summary> ```typescript class Collection<T> implements Iterable<T> { private items: T[] = []; add(item: T): void { this.items.push(item); } remove(item: T): boolean { const index = this.items.indexOf(item); if (index > -1) { this.items.splice(index, 1); return true; } return false; } removeAt(index: number): T | undefined { if (index < 0 || index >= this.items.length) { return undefined; } return this.items.splice(index, 1)[0]; } get(index: number): T | undefined { return this.items[index]; } contains(item: T): boolean { return this.items.includes(item); } size(): number { return this.items.length; } isEmpty(): boolean { return this.items.length === 0; } clear(): void { this.items = []; } toArray(): T[] { return […this.items]; } 高阶函数 filter(predicate: (item: T) ⇒ boolean): Collection<T> { const result = new Collection<T>(); for (const item of this.items) { if (predicate(item)) { result.add(item); } } return result; } map<U>(transform: (item: T) ⇒ U): Collection<U> { const result = new Collection<U>(); for (const item of this.items) { result.add(transform(item)); } return result; } reduce<U>(reducer: (acc: U, item: T) ⇒ U, initial: U): U { let accumulator = initial; for (const item of this.items) { accumulator = reducer(accumulator, item); } return accumulator; } find(predicate: (item: T) ⇒ boolean): T | undefined { return this.items.find(predicate); } every(predicate: (item: T) ⇒ boolean): boolean { return this.items.every(predicate); } some(predicate: (item: T) ⇒ boolean): boolean { return this.items.some(predicate); } 实现迭代器 [Symbol.iterator](): Iterator<T> { let index = 0; const items = this.items; return { next(): IteratorResult<T> { if (index < items.length) { return { value: items[index++], done: false }; } return { value: undefined as any, done: true }; } }; } 排序 sort(compareFn?: (a: T, b: T) ⇒ number): Collection<T> { const result = new Collection<T>(); result.items = […this.items].sort(compareFn); return result; } 反转 reverse(): Collection<T> { const result = new Collection<T>(); result.items = […this.items].reverse(); return result; } } 使用 const numbers = new Collection<number>(); numbers.add(5); numbers.add(2); numbers.add(8); numbers.add(1); console.log([…numbers]); [5, 2, 8, 1] const evens = numbers.filter(n ⇒ n % 2 === 0); console.log([…evens]); [2, 8] const doubled = numbers.map(n ⇒ n * 2); console.log([…doubled]); [10, 4, 16, 2] const sum = numbers.reduce((acc, n) ⇒ acc + n, 0); console.log(sum); 16 const sorted = numbers.sort((a, b) ⇒ a - b); console.log([…sorted]); [1, 2, 5, 8] ``` </details> ===== 扩展阅读 ===== - 下一章:泛型 - TypeScript 官方文档 - 类