TypeScript 提供了多种访问修饰符来控制类成员的可见性和可修改性。合理使用这些修饰符可以实现良好的封装,提高代码的安全性和可维护性。
public 修饰符#
public 是默认的访问修饰符,成员可以在任何地方访问:
// TypeScript 5.x
class User { public name: string // 显式声明 public age: number // 默认就是 public
public constructor(name: string, age: number) { this.name = name this.age = age }
public greet(): string { return `Hello, ${this.name}` }}
const user = new User('张三', 25)console.log(user.name) // ✅ 可以访问console.log(user.age) // ✅ 可以访问user.name = '李四' // ✅ 可以修改private 修饰符#
private 成员只能在类内部访问:
class BankAccount { private balance: number
constructor(initialBalance: number) { this.balance = initialBalance }
public deposit(amount: number): void { if (amount > 0) { this.balance += amount this.logTransaction('deposit', amount) } }
public withdraw(amount: number): boolean { if (amount > 0 && amount <= this.balance) { this.balance -= amount this.logTransaction('withdraw', amount) return true } return false }
public getBalance(): number { return this.balance }
private logTransaction(type: string, amount: number): void { console.log(`${type}: ${amount}, Balance: ${this.balance}`) }}
const account = new BankAccount(1000)account.deposit(500)// account.balance; // ❌ 错误:私有属性// account.logTransaction('test', 100); // ❌ 错误:私有方法console.log(account.getBalance()) // ✅ 1500TypeScript private vs ES2022 #private#
// TypeScript private(编译时检查)class A { private x: number = 1}
// ES2022 原生私有字段(运行时强制)class B { #x: number = 1
getX() { return this.#x }}
// 区别:// 1. TypeScript private 编译后变成普通属性,可被绕过// 2. # 语法是真正的私有,运行时也无法访问// 3. # 语法不能与 private 修饰符一起使用protected 修饰符#
protected 成员可以在类内部和子类中访问:
class Animal { protected name: string protected age: number
constructor(name: string, age: number) { this.name = name this.age = age }
protected makeSound(): void { console.log('Some sound') }}
class Dog extends Animal { private breed: string
constructor(name: string, age: number, breed: string) { super(name, age) this.breed = breed }
public introduce(): string { // ✅ 可以访问 protected 成员 return `我是 ${this.name},${this.age} 岁,品种是 ${this.breed}` }
public bark(): void { this.makeSound() // ✅ 可以调用 protected 方法 console.log('汪汪!') }}
const dog = new Dog('旺财', 3, '柴犬')console.log(dog.introduce())// dog.name; // ❌ 错误:protected 成员不能在外部访问// dog.makeSound(); // ❌ 错误protected constructor#
// 受保护的构造函数,不能直接实例化class Base { protected constructor(public id: string) {}}
// const base = new Base('1'); // ❌ 错误:构造函数受保护
class Derived extends Base { constructor( id: string, public name: string ) { super(id) // ✅ 子类可以调用 }
static create(id: string, name: string): Derived { return new Derived(id, name) }}
const derived = new Derived('1', '测试')// 或使用工厂方法const derived2 = Derived.create('2', '测试2')readonly 修饰符#
readonly 属性只能在声明时或构造函数中赋值:
class Config { readonly apiUrl: string readonly timeout: number readonly version = '1.0.0' // 声明时赋值
constructor(apiUrl: string, timeout: number) { this.apiUrl = apiUrl // 构造函数中赋值 this.timeout = timeout }
// ❌ 不能在其他方法中赋值 // updateUrl(url: string) { // this.apiUrl = url; // 错误 // }}
const config = new Config('https://api.example.com', 5000)// config.apiUrl = 'xxx'; // ❌ 错误:只读属性readonly 与 const 的区别#
class Example { readonly prop = 1 // 只读属性
method() { const local = 2 // 常量变量 // local = 3; // ❌ 错误 // this.prop = 3; // ❌ 错误 }}
// readonly 用于属性,const 用于变量// 两者都表示不可重新赋值static 修饰符#
static 成员属于类本身,而不是实例:
class Counter { static count: number = 0 static readonly MAX_COUNT = 100
id: number
constructor() { Counter.count++ this.id = Counter.count }
static getCount(): number { return Counter.count }
static reset(): void { Counter.count = 0 }}
const c1 = new Counter()const c2 = new Counter()const c3 = new Counter()
console.log(Counter.count) // 3console.log(Counter.getCount()) // 3console.log(c1.id, c2.id, c3.id) // 1, 2, 3
Counter.reset()console.log(Counter.count) // 0静态块(ES2022)#
class Database { static connection: Connection static isInitialized = false
// 静态初始化块 static { try { Database.connection = createConnection() Database.isInitialized = true console.log('Database initialized') } catch (error) { console.error('Failed to initialize database') } }}修饰符组合#
修饰符可以组合使用:
class Example { public readonly id: string private readonly secret: string protected static count: number = 0
constructor(id: string, secret: string) { this.id = id this.secret = secret Example.count++ }
// 静态私有方法 private static log(message: string): void { console.log(`[Example] ${message}`) }
// 受保护的静态属性 protected static getCount(): number { return Example.count }}参数属性与修饰符#
class User { constructor( public readonly id: string, public name: string, private password: string, protected role: string = 'user' ) {}
checkPassword(input: string): boolean { return this.password === input }}
const user = new User('1', '张三', 'secret123')console.log(user.id) // ✅console.log(user.name) // ✅// user.id = '2'; // ❌ readonly// user.password; // ❌ private访问性对比#
| 修饰符 | 类内部 | 子类 | 实例 |
|---|---|---|---|
| public | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ❌ |
| private | ✅ | ❌ | ❌ |
实际应用模式#
单例模式#
class Singleton { private static instance: Singleton private constructor(public value: string) {}
static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton('singleton value') } return Singleton.instance }}
const s1 = Singleton.getInstance()const s2 = Singleton.getInstance()console.log(s1 === s2) // true工厂模式#
class Product { private constructor( public readonly id: string, public readonly name: string, public readonly price: number ) {}
static create(name: string, price: number): Product { const id = Math.random().toString(36).substr(2, 9) return new Product(id, name, price) }
static createFromJson(json: string): Product { const data = JSON.parse(json) return new Product(data.id, data.name, data.price) }}
const product = Product.create('手机', 5999)console.log(product.id, product.name, product.price)封装状态#
class StateMachine { private currentState: string private readonly transitions: Map<string, string[]>
constructor(initialState: string) { this.currentState = initialState this.transitions = new Map() }
addTransition(from: string, to: string): this { const existing = this.transitions.get(from) || [] existing.push(to) this.transitions.set(from, existing) return this }
transition(to: string): boolean { const allowed = this.transitions.get(this.currentState) || [] if (allowed.includes(to)) { this.currentState = to return true } return false }
get state(): string { return this.currentState }}
const machine = new StateMachine('idle') .addTransition('idle', 'running') .addTransition('running', 'paused') .addTransition('running', 'stopped') .addTransition('paused', 'running')
machine.transition('running') // trueconsole.log(machine.state) // "running"常见问题#
🙋 private 成员会被继承吗?#
会被继承,但不能访问:
class Parent { private secret = 'secret'}
class Child extends Parent { reveal() { // return this.secret; // ❌ 错误:不能访问 return 'Cannot access parent private' }}🙋 静态成员可以访问实例成员吗?#
不能直接访问:
class Example { instanceProp = 'instance'
static staticMethod() { // console.log(this.instanceProp); // ❌ 错误 }
static staticMethodWithInstance(instance: Example) { console.log(instance.instanceProp) // ✅ 通过参数访问 }}🙋 如何让属性只在类内部可写?#
结合 private 和 public getter:
class Counter { private _count = 0
get count(): number { return this._count }
increment(): void { this._count++ }}
const counter = new Counter()console.log(counter.count) // ✅ 可读// counter.count = 10; // ❌ 没有 setter,不可写counter.increment() // ✅ 通过方法修改总结#
| 修饰符 | 作用 | 适用场景 |
|---|---|---|
| public | 公开访问 | 公共 API |
| private | 仅类内部 | 内部实现细节 |
| protected | 类和子类 | 可继承的内部成员 |
| readonly | 只读 | 不变的配置、常量 |
| static | 类级别 | 工具方法、单例、常量 |
下一篇我们将学习类的继承,包括 extends、super 和方法重写。