什么是装饰器?
装饰器本质上是一个函数,用来扩展类和类的成员
启用装饰器语法
为了能够使用装饰器语法,需要在 tsconfig.json 中将 experimentalDecorators 开启,以此来消除警告。
装饰器用法
因为装饰器本身是一个函数,并且它可以用来修饰类
那么,它的参数意味着什么?
这个 target 是什么?
实际上,这个 target 就是 class Animal,它指向类本身
另外,target 除了指向类之外,就是类的原型了。
将 ts 文件编译成 js 文件后
可以看到在__decorate 方法中第二个参数就为 target,而其对应的值就是 Animal。
那么,还有一个疑问:为什么__decorate 方法可以传一个 Decorator 数组?
因为,一个类可以有多个装饰器,并且在最后通过 d 函数去处理装饰器,将结果赋值给 r,最后返回 r。
再观察循环的方式,可以发现:装饰器是倒序执行的,也就是说先执行离自己最近的那个装饰器,再向上执行。实际上,整个执行的流程有点类似于洋葱模型。
扩展类的属性和原型
返回子类,这个子类用于重写父类
扩展类中的方法
(装饰器函数在修饰成员函数时一定会执行,无论有没有创建实例)
扩展属性访问器
通过这些例子,可以感知出来:
- 如果需要在装饰器中传参的话,需要在装饰器函数外先包一层,但最终还是需要返回一个函数。
装饰器的执行流程
一直会是这个固定的顺序吗?
不是。
倘若将静态方法装饰器和静态属性装饰器交换位置,会出现如下图:
由此可得出:方法和属性之间没有顺序关系,谁先写谁先执行。
那么,根据此结论,可以将代码这样分:
这里可能会有一个疑问:明明实例/原型方法装饰器写在了函数参数装饰器之上,怎么和之前说的不一样?
其实很好理解,执行函数时肯定要先找参数,随后在执行函数体中的逻辑,来完成函数的功能。所以会先执行函数参数装饰器,再执行实例/原型方法装饰器。
但整个装饰器执行的流程不变,总体分为:实例 -> 静态 -> 构造函数 -> 类。