TypeScript系列教程十一《装饰器》 -- 类装饰器

2022-05-06 17:19:13 浏览数 (1)

类装饰器顾名思义是对类的内容进行修饰,在Typescript 类其实就是对象,这样配合原型对象操作可以达到操作类的目的。

类装饰器定义

首先看下类装饰器在TS中的定义:

  • 是一个函数
  • 函数的参数是一个继承函数类型的泛型函数
  • 返回可以是一个装饰器函数或者不返回(工厂模式返回函数后面介绍)
代码语言:javascript复制
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

类装饰器

案例思路描述:

  1. 创建一个学生类
  2. 让学生类具拥有谈钢琴的技能
  3. 同时艺术家也想拥有弹钢琴的技能

我们用组合的思想,可以将弹钢琴的技能部分单独实现出来,谁想拥有引入即可。

装饰器相同的道理,只需要实现这个装饰器即可,下面用代码实现。

代码语言: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 {
}

打印结果:

结论:

装饰器嵌套相当于 函数嵌套,先执行后面的装饰器,当后面的装饰器执行完,才执行前面的。

0 人点赞