什么是 TypeScript 类?
在 JavaScript 的世界里,我们常用函数和对象来组织代码。但当项目变得复杂时,这种写法容易导致代码难以维护。TypeScript 为解决这个问题引入了“类”这个概念,它让面向对象编程变得更加清晰、安全和可扩展。
你可以把 TypeScript 类想象成一个“模板”或“蓝图”。就像建筑师会先画一张建筑图纸,再根据图纸盖房子一样,类就是定义对象结构的蓝图。有了类,我们就能批量创建具有相同属性和方法的对象,而不会重复写一堆重复的代码。
TypeScript 类不仅支持传统的面向对象特性(如封装、继承、多态),还通过类型系统增强了代码的可读性和可维护性。比如,你可以在定义类的时候就明确告诉 TypeScript:这个属性必须是字符串,那个方法返回的是数字。
这就像你给快递包裹贴上标签——“易碎品”“请勿倒置”——这样无论是你自己还是别人,都能清楚地知道该如何处理。类型系统就是这样的标签系统,它帮助我们在开发阶段就发现潜在错误。
类的基本语法与结构
TypeScript 类的语法非常直观,和 Java、C# 等语言很相似。下面我们来创建一个最简单的类。
class Person {
// 属性(字段)
name: string;
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 方法
introduce(): string {
return `你好,我叫 ${this.name},今年 ${this.age} 岁。`;
}
}
逐行解释
class Person:声明一个名为Person的类,它是所有人类对象的模板。name: string和age: number:定义两个属性,分别表示姓名和年龄,类型明确为字符串和数字。constructor:构造函数,用于在创建对象实例时初始化属性。每次new Person(...)被调用时,这个函数就会执行一次。this.name = name:this指向当前实例对象,把传入的参数赋值给对象的属性。introduce()方法:返回一段自我介绍的文字,使用了模板字符串(ES6 特性)。
现在我们来用这个类创建一个真实的人:
const person1 = new Person("小明", 25);
console.log(person1.introduce()); // 输出:你好,我叫 小明,今年 25 岁。
这样,我们就从“蓝图”造出了一个“人”。这个过程叫做实例化,new 关键字就是用来生成实例的。
属性修饰符:控制访问权限
TypeScript 类支持三种访问修饰符,它们像“门锁”一样控制属性和方法的可见性。
| 修饰符 | 含义 | 可见范围 |
|---|---|---|
public |
公开的 | 所有地方都能访问(默认) |
private |
私有的 | 只能在类内部访问 |
protected |
受保护的 | 类内部和子类中可访问 |
示例:使用 private 限制访问
class BankAccount {
private balance: number; // 私有属性:外部无法直接读写
constructor(initialBalance: number) {
this.balance = initialBalance;
}
// 公共方法:控制如何查看余额
getBalance(): number {
return this.balance;
}
// 公共方法:控制如何存钱
deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
console.log(`成功存入 ${amount} 元,当前余额为 ${this.balance} 元`);
} else {
console.log("存款金额必须大于 0");
}
}
// 公共方法:控制如何取钱
withdraw(amount: number): void {
if (amount > this.balance) {
console.log("余额不足,无法取款");
} else {
this.balance -= amount;
console.log(`成功取出 ${amount} 元,当前余额为 ${this.balance} 元`);
}
}
}
// 使用示例
const account = new BankAccount(1000);
account.deposit(500); // 成功存入 500 元,当前余额为 1500 元
account.withdraw(200); // 成功取出 200 元,当前余额为 1300 元
console.log(account.getBalance()); // 1300
// account.balance = 9999; // ❌ 编译错误!不能直接访问私有属性
💡 小贴士:
private能防止外部随意修改关键数据,比如银行账户余额。这就像你的手机密码,只有你自己知道,别人不能随便改。
构造函数与参数属性简化
当类的属性和构造函数参数一致时,可以使用“参数属性”语法来简化代码。
传统写法 vs 简化写法
// 传统方式:先声明属性,再在构造函数中赋值
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
// 简化方式:直接在构造函数参数前加修饰符
class Point {
constructor(
public x: number, // 相当于声明了 x 属性,并赋值
public y: number // 相当于声明了 y 属性,并赋值
) {}
}
效果完全一样,但代码更简洁。这种写法在实际项目中非常常见,尤其适合用于 DTO(数据传输对象)或配置类。
继承与多态:构建类的层次结构
在现实世界中,我们经常看到“父子关系”。比如“汽车”是“交通工具”的一种,“电动车”又是“汽车”的一种。TypeScript 类也支持这种继承机制。
基类与子类
// 基类:交通工具
class Vehicle {
protected speed: number = 0;
start(): void {
console.log("交通工具启动中...");
}
stop(): void {
console.log("交通工具已停止");
}
// 抽象方法:子类必须实现
abstract getSpeed(): number;
}
// 子类:汽车
class Car extends Vehicle {
private wheels: number = 4;
getSpeed(): number {
return this.speed;
}
accelerate(): void {
this.speed += 10;
console.log(`汽车加速,当前速度:${this.speed} km/h`);
}
// 重写父类方法
start(): void {
console.log("汽车引擎启动,准备出发!");
}
}
// 子类:自行车
class Bicycle extends Vehicle {
private wheels: number = 2;
getSpeed(): number {
return this.speed;
}
pedal(): void {
this.speed += 5;
console.log(`自行车踩踏,当前速度:${this.speed} km/h`);
}
start(): void {
console.log("自行车骑上,准备出发!");
}
}
使用继承的实例
const car = new Car();
const bike = new Bicycle();
car.start(); // 输出:汽车引擎启动,准备出发!
car.accelerate(); // 输出:汽车加速,当前速度:10 km/h
bike.start(); // 输出:自行车骑上,准备出发!
bike.pedal(); // 输出:自行车踩踏,当前速度:5 km/h
🌟 多态的魅力在于:你可以统一用父类类型来引用子类对象,而程序会自动调用对应的方法。
const vehicles: Vehicle[] = [car, bike];
vehicles.forEach(v => {
v.start(); // 根据实际类型调用不同版本的 start()
});
这就像你对“交通工具”说“启动”,不管是汽车还是自行车,它们都会按自己的方式启动。
静态成员与单例模式
有时我们需要一些“属于类本身”的属性或方法,而不是属于某个实例。这就需要用到 static 关键字。
静态属性与方法
class MathUtils {
// 静态属性:类级别的常量
static PI: number = 3.14159;
// 静态方法:可以直接通过类名调用,无需创建实例
static square(x: number): number {
return x * x;
}
static add(a: number, b: number): number {
return a + b;
}
}
// 使用静态成员
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.square(4)); // 16
console.log(MathUtils.add(3, 7)); // 10
单例模式:确保只有一个实例
class Database {
private static instance: Database | null = null;
private constructor() {
console.log("数据库连接已建立");
}
// 获取唯一实例
static getInstance(): Database {
if (Database.instance === null) {
Database.instance = new Database();
}
return Database.instance;
}
query(sql: string): void {
console.log(`执行 SQL: ${sql}`);
}
}
// 使用单例
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true,是同一个实例
db1.query("SELECT * FROM users"); // 执行 SQL: SELECT * FROM users
✅ 单例模式常用于数据库连接、日志记录器、配置管理器等场景,避免重复创建资源。
实战项目:构建一个简易的学生管理系统
让我们用 TypeScript 类来构建一个真实可用的系统。
class Student {
private id: string;
private name: string;
private grades: number[] = [];
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
// 添加成绩
addGrade(grade: number): void {
if (grade < 0 || grade > 100) {
console.log("成绩必须在 0 到 100 之间");
return;
}
this.grades.push(grade);
}
// 计算平均分
getAverage(): number {
if (this.grades.length === 0) return 0;
const sum = this.grades.reduce((a, b) => a + b, 0);
return Math.round((sum / this.grades.length) * 100) / 100;
}
// 获取信息
getInfo(): string {
return `学号:${this.id},姓名:${this.name},平均分:${this.getAverage()}`;
}
}
// 使用示例
const student = new Student("S001", "张三");
student.addGrade(85);
student.addGrade(92);
student.addGrade(78);
console.log(student.getInfo()); // 学号:S001,姓名:张三,平均分:85
这个系统虽然简单,但体现了类的核心优势:封装数据和行为,提高代码复用性。
总结
TypeScript 类是构建复杂应用的基石。它让代码更清晰、更安全、更容易维护。从基础语法到访问控制,再到继承、静态成员和设计模式,每一步都为你提供更强大的编程能力。
无论是开发前端应用、后端服务,还是构建工具库,掌握 TypeScript 类都能让你的代码质量跃上一个台阶。它不只是语法糖,更是一种思维方式的升级。
当你开始用类来组织代码时,你就不再是“写代码”,而是在“设计系统”。这正是现代 JavaScript 开发的真正魅力所在。
如果你正在学习 TypeScript,不妨从一个简单的 Person 类开始,一步步构建你的第一个“对象世界”。