Class 与封装
面向对象编程会把程序中的数据和功能组织到对象中。TypeScript 通过 class 定义对象模型,通过访问修饰符控制数据的访问范围。
一、类和对象的关系
- 类是对象的模型或模板。
- 对象是根据类创建出来的实例。
- 属性用于保存数据。
- 方法用于描述对象的行为。
例如,可以使用 Person 类创建多个不同的人对象。
二、定义一个类
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(): void {
console.log('大家好,我是' + this.name);
}
}
通过 new 创建实例:
const person = new Person('孙悟空', 18);
person.sayHello();
三、构造函数和 this
构造函数使用 constructor 声明,在创建实例时自动执行。this 表示当前实例对象。
class User {
username: string;
constructor(username: string) {
this.username = username;
}
}
构造函数参数也可以直接声明为属性,这种写法叫参数属性:
class Product {
constructor(
public name: string,
public price: number
) {}
}
const product = new Product('键盘', 299);
四、访问修饰符
TypeScript 中常见的访问修饰符有三个:
| 修饰符 | 类内部 | 子类 | 类外部对象 |
|---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 |
protected | 可以访问 | 可以访问 | 不能访问 |
private | 可以访问 | 不能访问 | 不能访问 |
1. public
public 是默认修饰符,省略修饰符时也表示公开成员:
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person('孙悟空');
person.name = '猪八戒';
2. protected
protected 成员只能在当前类和子类中访问:
class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Employee extends Person {
printName(): void {
console.log(this.name);
}
}
const employee = new Employee('唐僧');
employee.printName();
// 编译错误:类外部不能直接访问 protected 成员
// employee.name;
3. private
private 成员只能在当前类内部访问:
class Account {
private balance: number;
constructor(balance: number) {
this.balance = balance;
}
getBalance(): number {
return this.balance;
}
}
const account = new Account(1000);
console.log(account.getBalance());
// 编译错误:类外部不能直接访问 private 成员
// account.balance;
五、readonly 只读属性
使用 readonly 可以限制属性不能被重新赋值:
class User {
readonly id: number;
constructor(id: number) {
this.id = id;
}
}
const user = new User(1001);
// 编译错误:id 是只读属性
// user.id = 1002;
readonly 属性通常可以在声明时或构造函数中初始化,之后不能再次修改。
六、属性存取器 getter 和 setter
当属性需要被保护,但又希望对外提供读取或修改入口时,可以使用属性存取器。
get用于读取属性。set用于修改属性。
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name(): string {
return this._name;
}
set name(name: string) {
if (name.trim() !== '') {
this._name = name;
}
}
}
const person = new Person('孙悟空');
console.log(person.name);
person.name = '猪八戒';
调用存取器时不需要写括号,使用方式和普通属性类似。
七、静态属性和静态方法
使用 static 声明的成员属于类本身,不属于某个实例。使用静态成员时不需要创建对象。
class Tools {
static PI: number = 3.1415926;
static sum(num1: number, num2: number): number {
return num1 + num2;
}
}
console.log(Tools.PI);
console.log(Tools.sum(123, 456));
实例成员通过对象访问,静态成员通过类名访问:
实例成员 → person.name
静态成员 → Tools.PI
八、封装的意义
封装就是把数据和操作数据的方法放在一起,并限制外部直接修改内部状态。
例如账户余额不应该被随意修改,可以通过方法控制业务规则:
class BankAccount {
private balance: number;
constructor(balance: number) {
this.balance = balance;
}
deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
}
}
getBalance(): number {
return this.balance;
}
}
九、常见问题
1. 把 private 当成运行时绝对安全
private 主要由 TypeScript 在编译阶段检查。它的作用是约束代码访问方式,而不是替代真正的安全机制。
2. 直接公开所有属性
如果属性有合法范围或业务规则,建议使用 private 配合方法或存取器进行控制。
3. 在静态方法中直接访问实例属性
静态方法没有具体实例,不能直接访问实例成员:
class Example {
name: string = 'demo';
static print(): void {
// 不能直接访问 this.name
// console.log(this.name);
}
}
十、本章小结
class用于定义对象模型。constructor用于初始化实例。public、protected、private用于控制访问范围。readonly可以保护只读数据。get和set可以安全地读取和修改私有属性。static成员属于类本身,不需要创建实例。

448

被折叠的 条评论
为什么被折叠?



