访问修饰符控制类成员的可访问性,是封装的关键机制。TypeScript 提供了三种访问修饰符:
public、private和protected,分别对应不同的访问级别。
public 修饰的成员可以在任何地方访问,这是默认的访问级别。
class User {
public name: string
public age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
public greet(): string {
return `你好,我是 ${this.name}`
}
}
const user = new User("张三", 25)
console.log(user.name)
console.log(user.greet())
name、age 和 greet 方法都是公共成员,可以在类外部自由访问。省略修饰符时默认就是 public。
private 修饰的成员只能在类内部访问,外部无法直接访问。
class BankAccount {
private balance: number
constructor(initialBalance: number) {
this.balance = initialBalance
}
deposit(amount: number): void {
if (amount > 0) {
this.balance += amount
console.log(`存入 ${amount},余额 ${this.balance}`)
}
}
withdraw(amount: number): boolean {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount
console.log(`取出 ${amount},余额 ${this.balance}`)
return true
}
console.log("取款失败")
return false
}
getBalance(): number {
return this.balance
}
}
const account = new BankAccount(1000)
account.deposit(500)
account.withdraw(200)
console.log(account.getBalance())
balance 是私有属性,外部无法直接修改,只能通过 deposit 和 withdraw 方法操作。这保证了数据的安全性。
protected 修饰的成员可以在类内部和子类中访问,但不能在类外部访问。
class Component {
protected state: any
protected props: any
constructor(props: any) {
this.props = props
this.state = {}
}
protected setState(newState: any): void {
this.state = { ...this.state, ...newState }
}
}
class Button extends Component {
constructor(props: any) {
super(props)
}
click(): void {
this.setState({ clicked: true })
console.log("按钮被点击", this.state)
}
}
const button = new Button({ text: "提交" })
button.click()
state 和 props 是受保护成员,子类 Button 可以访问它们,但外部代码无法直接访问。
在构造函数参数上添加访问修饰符,可以同时声明和初始化属性。
class Product {
constructor(
public name: string,
public price: number,
private stock: number,
protected category: string
) {}
getStock(): number {
return this.stock
}
}
const product = new Product("手机", 2999, 100, "电子产品")
console.log(product.name)
console.log(product.price)
console.log(product.getStock())
这种简写方式减少了样板代码,让类定义更加简洁。name 和 price 是公共属性,stock 是私有属性,category 是受保护属性。
三种访问修饰符的可访问范围如下:
| 修饰符 | 类内部 | 子类 | 类外部 |
|---|---|---|---|
| public | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✗ |
| private | ✓ | ✗ | ✗ |
选择合适的访问级别是良好封装的关键。通常将数据设为私有,通过公共方法提供受控的访问。
TypeScript 还支持 JavaScript 的私有字段语法,使用 # 前缀。
class Counter {
#count: number = 0
increment(): void {
this.#count++
}
decrement(): void {
this.#count--
}
getCount(): number {
return this.#count
}
}
const counter = new Counter()
counter.increment()
counter.increment()
console.log(counter.getCount())
#count 是真正的私有字段,即使在运行时也无法从外部访问。这与 private 不同,private 只在编译时检查,运行时仍然可以访问。
访问修饰符可以与存取器配合使用,实现更精细的访问控制。
class User {
private _password: string = ""
get password(): string {
return "******"
}
set password(value: string) {
if (value.length >= 6) {
this._password = value
} else {
console.log("密码长度至少6位")
}
}
validatePassword(input: string): boolean {
return this._password === input
}
}
const user = new User()
user.password = "123456"
console.log(user.password)
console.log(user.validatePassword("123456"))
_password 是私有属性,外部无法直接读取。通过存取器,我们控制了密码的设置和显示方式。
访问修饰符在实际开发中有很多应用场景。比如实现单例模式:
class Database {
private static instance: Database
private connection: any
private constructor() {
this.connection = {}
}
static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database()
}
return Database.instance
}
query(sql: string): any {
console.log(`执行查询: ${sql}`)
return []
}
}
const db1 = Database.getInstance()
const db2 = Database.getInstance()
console.log(db1 === db2)
构造函数设为私有,外部无法直接创建实例,只能通过 getInstance 方法获取唯一的实例。
访问修饰符是封装的核心工具。public 允许任意访问,private 限制只能在类内部访问,protected 允许子类访问。合理使用访问修饰符可以保护数据安全,控制类的接口,提高代码的可维护性。在实际开发中,应该默认使用最小的访问级别,只在必要时开放访问权限。