一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
1.类的装饰器:
装饰器是啥?装饰第一个想到的就是emmm...女票化妆...装修...,当然笔者怎么可能让女票影响自己写blog呢?我不配,哈哈哈哈...
- 装饰器呢,直白点就是让就好比
女生的化妆品,女生通过化妆品能够变的漂亮,而类通过装饰器,让类变的也更加强大。 - 装饰器本身其实就是一个函数
例子:
class Iverson{
}
// const sevenSixers = new Iverson();
// console.log((sevenSixers as any).getName()) //会报错-sevenSixers.getName is not a function
function goDecorator(constructor:any){
console.log('我是韦德')
constructor.prototype.getName = ()=>{
console.log('我是热火队的德怀恩-韦德')
}
}
function nextDecorator(constructor:any){
console.log('我是转会到骑士队的韦德')
}
@goDecorator //后被打印
@nextDecorator //先被打印
class Wade{
}
const player =new Wade();
const player1 =new Wade();
console.log((player as any).getName()); //我是热火队的德怀恩-韦德
解析:
-
类的装饰器使用是通过
@ + 函数名放在类前面 -
类的装饰器运行时机:
类创建好之后,立刻就会去执行 -
(sevenSixers as any).getName()这种方式可以解决报错,但是不要随便用 -
类的装饰器是针对于类的,多次实例化也只会打印出一次
'我是韦德'; -
goDecorator(nextDecorator(Class Wade{}))---可以理解为近的先执行
通过工厂模式加壳子:
//工厂模式
function decorator(flag:boolean){
if(flag){
return function(constructor:any){
constructor.prototype.getName = ()=>{
console.log('工厂模式')
}
}
}else{
return function(constructor:any){};
}
}
@decorator(true)
class Go{
}
const runner = (new Go() as any).getName();
console.log(runner); // 工厂模式
解析:
- 类似于闭包,在第一个函数内部做些处理,然后返回一个新的函数作为装饰器。
@decorator(true)传参数,然后在内部判断
更加优雅的方式:
为了不让typescript成为anyscript
function decorator1<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor{
//这里对原来的构造函数进行了修改
name = 'lee';
}
}
@decorator1
class Going {
name:string;
constructor(name:string){
this.name = name;
}
}
const runner1 = (new Going('艾弗森'));
console.log(runner1); // {name:lee}
解析:
-
new的意思是这是一个构造函数,可以接受多个参数,每个参数的类型都是anyT extends new (...args: any[]) => any:T继承自一个构造函数
-
打印结果不再是
艾弗森,而是lee,老的构造函数会先执行,然后再去执行装饰器decorate1中的内容,从而完成了从艾弗森到lee的转变
接下来看下面的例子,我们想要通过在装饰器中添加getName方法,从而让Going类的实例上都具有getName方法,为什么会失败呢?
- 通过装饰器添加到类中的方法不会在实例化的时候被
typescript识别出来
function decorator1<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor{
name = 'lee';
getName(){
return this.name;
}
}
}
@decorator1
class Going {
name:string;
constructor(name:string){
this.name = name;
}
}
const runner1 = (new Going('艾弗森'));
//这里通过装饰器加入的getName方法不会被typescript识别出来
console.log(runner1.getName());
那么如果就是想要通过装饰器在类的实例中添加方法,应该如何处理呢?
来看下面例子:
function decorator1(){
return function <T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor{
name = 'lee';
getName(){
return this.name;
}
}
}
}
const Going = decorator1()(class{
name:string;
constructor(name:string){
this.name = name;
}
})
const runner1 = (new Going('艾弗森'));
//这里现在不报错了
console.log(runner1.getName());//打印lee
- 通过让
装饰器函数返回一个接收类作为参数的函数的形式来实现,高阶函数
最后注意:tscofnig.json中需要将下面的项目开启,才能够使用装饰器
"experimentalDecorators": true,