修饰器

Youky ... 2023-6-20 前端
  • TS
About 2 min

# 修饰器

装饰器是 TS 中的一种语法,以 @ 开头,只能用于类和类成员(类、属性、方法、方法参数)。

其本质上是一个函数,只不过入参是提前确定的。通常使用工厂函数创建修饰器,这样使用时修饰器可以接受不同的参数。

# 类装饰器

类修饰器直接作用于类上,其接受唯一参数 target 是类本身。

通过类修饰器,可以读取类的信息,新增或覆盖类的属性与方法。通过修改 target 可以修改其静态属性,修改 target.prototype 可以修改其原型链上(可被实例化和继承)的属性。

function Add(num: number) {
  return function (target: any) {
    target.age = target.age + num
    target.prototype.num = num * 10
  }
}

@Add(1)
class People {
  static age = 1
}
const a = new People() as any
console.log(People.age) // 2
console.log(a.num) // 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如果在类修饰器中返回一个新的类,可以覆盖整个类的实现。:

function ReWrite(Target: any) {
  return class Sub extends Target {
    // 重写log方法
    static log(str: string) {
      console.log("new log")
    }
    // 子类新增的方法
    static print() {
      console.log("print")
    }
  }
}

@ReWrite
class Logger {
  static log(str: string) {
    console.log(str)
  }
}
Logger.log("abc")(
  // new log
  Logger as any
).print() // print
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 属性装饰器

# 方法装饰器

方法装饰器的入参包括类的原型(不是类本身)方法名以及方法的属性描述符(PropertyDescriptor),通过属性描述符可以控制这个方法的内部实现(value)、**可变性(writable)**等信息。

能拿到原本实现,也意味着,我们可以在执行原本方法的同时插入一段新的逻辑。比如计算函数执行耗时:

function TimeLog(target, name, descriptor: any) {
  const original = descriptor.value
  descriptor.value = async () => {
    const pre = Date.now()
    await original()
    const cost = Date.now() - pre
    console.log("Cost: ", cost)
  }
}
class Foo {
  @TimeLog
  static async fetch() {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(""), 3000)
    })
  }
}
Foo.fetch() // Cost:  3016
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 参数修饰器

# 访问符修饰器

Last update: June 20, 2023 23:47
Contributors: Youky