类装饰器顾名思义是对类的内容进行修饰,在Typescript 类其实就是对象,这样配合原型对象操作可以达到操作类的目的。
类装饰器定义
首先看下类装饰器在TS中的定义:
- 是一个函数
- 函数的参数是一个继承函数类型的泛型函数
- 返回可以是一个装饰器函数或者不返回(工厂模式返回函数后面介绍)
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
类装饰器
案例思路描述:
- 创建一个学生类
- 让学生类具拥有谈钢琴的技能
- 同时艺术家也想拥有弹钢琴的技能
我们用组合的思想,可以将弹钢琴的技能部分单独实现出来,谁想拥有引入即可。
装饰器相同的道理,只需要实现这个装饰器即可,下面用代码实现。
代码语言:javascript复制const musicDecorator : ClassDecorator = (target:Function)=>{
target.prototype.playPiano = () => {
console.log('弹钢琴');
}
}
@musicDecorator
class Student {
}
@musicDecorator
class Artist{
}
var xiaoming = new Student();
(<any>xiaoming).playPiano()
var jay = new Artist();
(<any>jay).playPiano()
控制台输出:
类装饰器原理
类装饰器其实就是一个语法糖,类装饰器相当于一个函数,函数的参数是类构造函数。
那么上面的例子我们完全可以这么写,输出结果一致:
代码语言:javascript复制const musicDecorator : ClassDecorator = (target:Function)=>{
target.prototype.playPiano = () => {
console.log('弹钢琴');
}
}
class Student {
}
class Artist{
}
//函数调用
musicDecorator(Student)
musicDecorator(Artist)
var xiaoming = new Student();
(<any>xiaoming).playPiano()
var jay = new Artist();
(<any>jay).playPiano()
工厂类装饰器
有些装饰器需要参数判断情况,比如学生和艺术家都能弹钢琴,但是弹的曲目不一样,那么需要带参数判断,工厂根据参数创造出装饰器返回。
代码思路:
- 学生类
- 艺术家类
- 工厂装饰器根据参数让学生弹 小星星,艺术家弹奏夜曲
下面看代码例子:
代码语言:javascript复制const musicDecorator:(song:string)=> ClassDecorator = (song)=>{
return (target:Function)=>{
target.prototype.playPiano = () => {
console.log(song);
}
}
}
@musicDecorator('小星星')
class Student {
}
@musicDecorator('小夜曲')
class Artist{
}
var xiaoming = new Student();
(<any>xiaoming).playPiano()
var jay = new Artist();
(<any>jay).playPiano()
控制台输出:
类装饰器组合
类装饰器和函数一样是可以叠加的,一般是可以这么想象的。
如下面的例子:(学生既可以弹钢琴,又有班级属性)
代码语言:javascript复制const musicDecorator:(song:string)=> ClassDecorator = (song)=>{
return (target:Function)=>{
target.prototype.playPiano = () => {
console.log(song);
}
}
}
const classNameDecorator:ClassDecorator = (target:Function)=>{
target.prototype.className = '三年二班'
}
@musicDecorator('小星星')
@classNameDecorator
class Student {
}
var xiaoming = new Student();
(<any>xiaoming).playPiano()
console.log((<any>xiaoming).className);
思考装饰叠加的执行顺序
验证案例思路:
- 两个装饰器
- 两个装饰器都往原型对象上加属性
- 查看调用顺序
示例代码:
代码语言:javascript复制const musicDecorator:ClassDecorator = (target:Function)=>{
console.log('执行musicDecorator');
console.log(target.prototype.className);
target.prototype.song = '小星星'
}
const classNameDecorator:ClassDecorator = (target:Function)=>{
console.log('执行classNameDecorator');
console.log(target.prototype.song);
target.prototype.className = '三年二班'
}
@classNameDecorator
@musicDecorator
class Student {
}
打印结果:
结论:
装饰器嵌套相当于 函数嵌套,先执行后面的装饰器,当后面的装饰器执行完,才执行前面的。