TypeScript类:面向对象编程的基石
一、从现实世界到代码世界
想象你要建造一栋房子,首先需要一张设计蓝图——它定义了房屋的结构(几个房间)、功能(卧室/厨房)和特性(材料/颜色)。在TypeScript中,class
就是这个设计蓝图,而根据蓝图建造出来的具体房屋就是对象实例。
二、类的核心组成
1. 基础类结构
class Smartphone {
// 属性声明
brand: string;
storage: number;
// 构造函数
constructor(brand: string, storage: number) {
this.brand = brand;
this.storage = storage;
}
// 方法
checkStorage(): string {
return `${this.storage}GB remaining`;
}
}
// 创建实例
const myPhone = new Smartphone("Pixel", 128);
console.log(myPhone.checkStorage()); // 输出:128GB remaining
2. 类成员修饰符
TypeScript通过访问修饰符增强了类的封装性:
修饰符 | 访问范围 | 示例代码 |
---|---|---|
public | 所有地方(默认) | public id: number |
private | 仅类内部 | private secret: string |
protected | 类及其子类 | protected key: string |
readonly | 只读属性 | readonly serial: string |
class BankAccount {
private _balance: number; // 真正存储值的私有字段
readonly accountNumber: string;
constructor(initial: number, num: string) {
this._balance = initial;
this.accountNumber = num;
}
public get balance(): number { // 访问器属性
return this._balance;
}
}
const account = new BankAccount(1000, "622588");
console.log(account.balance); // ✔ 允许访问
// account._balance = 5000; // ❌ 编译错误
3. 继承与多态
// 基类
class Animal {
constructor(public name: string) {}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m`);
}
}
// 派生类
class Snake extends Animal {
constructor(name: string) {
super(name); // 必须调用父类构造函数
}
// 方法重写
override move(distance = 5) {
console.log("Slithering...");
super.move(distance); // 调用父类方法
}
}
const sam = new Snake("Sammy");
sam.move(); // 输出:Slithering... Sammy moved 5m
三、高级类特性
1. 抽象类
abstract class Shape {
abstract getArea(): number; // 抽象方法
printArea() {
console.log(`Area: ${this.getArea()}`);
}
}
class Circle extends Shape {
constructor(public radius: number) {
super();
}
override getArea(): number {
return Math.PI * this.radius ** 2;
}
}
// const shape = new Shape(); // ❌ 错误:不能实例化抽象类
const circle = new Circle(5);
circle.printArea(); // 输出:Area: 78.5398...
2. 静态成员
class URLHelper {
static BASE_DOMAIN = "https://api.example.com";
static buildUserEndpoint(userId: number): string {
return `${this.BASE_DOMAIN}/users/${userId}`;
}
}
console.log(URLHelper.buildUserEndpoint(123));
// 输出:https://api.example.com/users/123
3. 方法重载
class Calculator {
// 方法重载签名
add(a: number, b: number): number;
add(a: string, b: string): string;
// 实现签名
add(a: any, b: any): any {
if (typeof a === "string") {
return a + b;
}
return a + b;
}
}
const calc = new Calculator();
console.log(calc.add(1, 2)); // 3
console.log(calc.add("1", "2"));// "12"
四、类与接口的协作
// 定义接口
interface Loggable {
log(): void;
}
// 实现接口
class FileLogger implements Loggable {
log() {
console.log("Writing to file...");
}
}
// 多接口实现
class DatabaseLogger implements Loggable {
log() {
console.log("Saving to database...");
}
connect() {
console.log("Connecting DB...");
}
}
五、最佳实践指南
-
单一职责原则
每个类应该只有一个引起变化的原因 -
组合优于继承
优先使用对象组合而不是类继承:
class Engine { /* ... */ }
class Car {
constructor(private engine: Engine) {}
}
-
明确访问控制
除非必要,否则属性都应设为private
-
避免深度继承
继承层级建议不超过3层 -
合理使用抽象
通过抽象类定义通用行为
六、常见误区提醒
❌ 误区1:认为private
是绝对安全的
实际上编译后的JavaScript中私有属性仍然可见
❌ 误区2:过度使用继承
导致类之间高度耦合,增加维护难度
❌ 误区3:忽略super()
调用
在派生类构造函数中忘记调用super()
会导致错误
七、类与JavaScript的差异
特性 | TypeScript | JavaScript ES6 |
---|---|---|
访问修饰符 | 支持public/private/protected | 无原生支持 |
抽象类 | 支持 | 不支持 |
接口实现 | 显式implements 语法 | 无 |
属性声明 | 类顶部显式声明 | 在构造函数中初始化 |
结语
TypeScript类不仅保留了JavaScript的灵活性,还通过类型系统和面向对象特性,帮助开发者构建更健壮的应用程序。掌握类的使用是成为TypeScript开发者的重要一步,但记住:真正的面向对象设计不在于使用多少高级语法,而在于如何用合理的抽象解决实际问题。
如果对你有帮助,请帮忙点个赞