Skip to content

属性装饰器

基本语法

ts
/**
 * 参数说明
 * @param target 对于静态属性来说值是类, 对于实例属性来说值是类的原型对象
 * @param propertyKey 属性名
 */
function Demo(target: object, propertyKey: string) {
  console.log(target, propertyKey) // {} 'name'
}

class Person {
  // 静态属性
  @Demo static school: string
  // 实例属性
  @Demo name: string
  @Demo age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  speak() {
    console.log('Halo')
  }
}

关于属性遮蔽

如下代码中, 当构造器中的this.age = age试图再实例上赋值时, 实际上是调用了原型上的age属性的set方法

ts
class Person {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
let value = 99
// 使用 Object.defineProperty 给 Person 原型添加 age 属性, 并配置对应的 get 和 set 方法
Object.defineProperty(Person.prototype, 'age', {
  get() {
    return value
  },
  set(v) {
    value = v
  },
})
const man = new Person('张三', 16)
console.log(man)

应用示例

需求: 定义一个State属性装饰器, 监听属性的修改

ts
function State(target: object, propertyKey: string) {
  // let value: any
  let key = `__${propertyKey}`
  Object.defineProperty(target, propertyKey, {
    get() {
      // return value
      return this[key]
    },
    set(v) {
      console.log(`${propertyKey}的最新值是: ${v}`)
      this[key] = v
      // value = v
    },
    enumerable: true, // 可枚举性
    configurable: true // 可配置性
  })
}

class Person {
  name: string
  @State age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

const man1 = new Person('张三', 18)
const man2 = new Person('李四', 20)

man1.age = 30
man2.age = 40
// console.log(man1.age, man2.age) // 40, 40
console.log(man1.age, man2.age) // 30, 40