存取器是类中特殊的属性访问方式,通过
get和set关键字定义。它们让我们可以在读取或设置属性时执行额外的逻辑,比如数据验证、格式转换或触发副作用。
使用 get 定义读取器,使用 set 定义设置器。存取器看起来像属性,但实际是方法调用。
class Person {
private _name: string = ""
get name(): string {
return this._name
}
set name(value: string) {
if (value.length > 0) {
this._name = value
}
}
}
const person = new Person()
person.name = "张三"
console.log(person.name)
name 看起来像普通属性,但实际通过存取器访问。设置时会检查值是否为空,读取时返回内部存储的 _name。
存取器最常见的用途是在设置属性时进行验证,确保数据的有效性。
class User {
private _age: number = 0
get age(): number {
return this._age
}
set age(value: number) {
if (value < 0) {
console.log("年龄不能为负数")
return
}
if (value > 150) {
console.log("年龄不合理")
return
}
this._age = value
}
}
const user = new User()
user.age = 25
console.log(user.age)
user.age = -5
user.age = 200
设置年龄时会检查范围,无效的值会被拒绝。这比直接暴露属性更安全。
存取器可以返回计算后的值,而不需要存储实际数据。
class Rectangle {
width: number
height: number
constructor(width: number, height: number) {
this.width = width
this.height = height
}
get area(): number {
return this.width * this.height
}
get perimeter(): number {
return 2 * (this.width + this.height)
}
}
const rect = new Rectangle(10, 20)
console.log(rect.area)
console.log(rect.perimeter)
area 和 perimeter 是计算属性,每次访问时都会重新计算。不需要单独存储这些值,它们总是与 width 和 height 保持同步。
只定义 get 不定义 set,就创建了只读属性。
class Counter {
private _count: number = 0
get count(): number {
return this._count
}
increment(): void {
this._count++
}
reset(): void {
this._count = 0
}
}
const counter = new Counter()
console.log(counter.count)
counter.increment()
counter.increment()
console.log(counter.count)
counter.reset()
console.log(counter.count)
count 是只读属性,外部无法直接修改,只能通过 increment 和 reset 方法改变。
存取器可以实现延迟初始化,只有在第一次访问时才创建资源。
class Database {
private _connection: any = null
get connection(): any {
if (!this._connection) {
console.log("建立数据库连接...")
this._connection = { connected: true }
}
return this._connection
}
query(sql: string): any {
return this.connection.query(sql)
}
}
const db = new Database()
console.log("数据库实例创建")
console.log(db.connection)
数据库连接在第一次访问 connection 属性时才创建,避免了不必要的资源消耗。
存取器可以在读写时进行格式转换。
class Product {
private _price: number = 0
get price(): string {
return `¥${this._price.toFixed(2)}`
}
set price(value: string) {
const num = parseFloat(value.replace(/[^\d.]/g, ""))
if (!isNaN(num) && num >= 0) {
this._price = num
}
}
get priceNumber(): number {
return this._price
}
}
const product = new Product()
product.price = "299.99"
console.log(product.price)
console.log(product.priceNumber)
product.price = "¥599.00"
console.log(product.price)
price 存取器处理字符串和数字之间的转换,内部存储数字,外部显示格式化的字符串。
存取器可以在设置值时触发其他操作。
class ViewModel {
private _data: any = {}
private _listeners: Array<(data: any) => void> = []
get data(): any {
return { ...this._data }
}
set data(value: any) {
this._data = value
this.notify()
}
subscribe(listener: (data: any) => void): void {
this._listeners.push(listener)
}
private notify(): void {
this._listeners.forEach(listener => listener(this._data))
}
}
const vm = new ViewModel()
vm.subscribe((data) => console.log("数据变化:", data))
vm.data = { name: "张三" }
vm.data = { name: "李四", age: 25 }
每次设置 data 时,都会通知所有订阅者。这是响应式编程的基础模式。
接口可以定义存取器的签名。
interface IProduct {
price: number
discount: number
finalPrice: number
}
class Product implements IProduct {
price: number
discount: number = 0
constructor(price: number) {
this.price = price
}
get finalPrice(): number {
return this.price * (1 - this.discount)
}
}
const product = new Product(100)
product.discount = 0.2
console.log(product.finalPrice)
接口定义了 finalPrice 属性,类通过存取器实现这个属性的计算逻辑。
存取器在每次访问时都会执行,如果有复杂计算,可能影响性能。
class DataProcessor {
private _data: number[] = []
private _cachedSum: number | null = null
get data(): number[] {
return [...this._data]
}
set data(value: number[]) {
this._data = value
this._cachedSum = null
}
get sum(): number {
if (this._cachedSum === null) {
console.log("计算总和...")
this._cachedSum = this._data.reduce((a, b) => a + b, 0)
}
return this._cachedSum
}
}
const processor = new DataProcessor()
processor.data = [1, 2, 3, 4, 5]
console.log(processor.sum)
console.log(processor.sum)
使用缓存可以避免重复计算。sum 存取器只在数据变化后第一次访问时计算,之后返回缓存值。
存取器提供了对属性访问的精细控制。通过 get 和 set,我们可以在读写属性时执行验证、转换、计算等操作。存取器让代码更加健壮,也更容易维护。在实际开发中,合理使用存取器可以封装复杂的逻辑,提供简洁的属性接口。