类的装饰器
2022-04-15 本文已影响0人
泡杯感冒灵
装饰器本身是一个函数,因为装饰器是对类进行修饰的,所以是类的装饰器,装饰器通过@符号来使用。
装饰器接受的参数是一个类的构造函数
function testDecorator (constructor: any) {
constructor.prototype.getName = () => {
console.log('weiyang');
};
}
@testDecorator(true)
class Test{ }
(test as any).getName()
装饰器的运行时机是类创建好后,立即执行,而不是实例化一个类的时候。
可以有多个装饰器,装饰器执行顺序是从下到上,从右到左。
function testDecorator1 (constructor: any) {
constructor.prototype.getName = () => {
console.log('yang1');
};
}
function testDecorator2 (constructor: any) {
constructor.prototype.getName = () => {
console.log('yang2');
};
}
@testDecorator1 @testDecorator2 class Test{ }
对装饰器做工厂模式的包装,就可以做一些参数上的判断了
function testDecorator(flag: boolean) {
if (flag) {
return function (constructor: any) {
constructor.prototype.getName = () => {
console.log('weiyang');
};
}
} else {
return function (constructor: any) {}
}
}
@testDecorator(true)
class Test{ }
const test = new Test();
(test as any).getName()
上边装饰器的写法,我们通过test .getName()
的时候,不会主动提示。所以不是一种特别正规的装饰器的写法。正规的怎么写呢?
function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
// 这里改造的构造函数后执行
return class extends constructor{
name = 'lee';
getName() {
return this.name;
}
}
}
@testDecorator
class Test{
name: string;
// 这个构造函数先执行
constructor(name: string) {
this.name = name;
}
}
const test = new Test('yang');
console.log((test as any).getName()); // 没有改造构造函数之前返回 {name:'yang'},改造之后返回 {name:'lee'}
- <T extends new (...args:any[]) => any>解析一下这个泛型,泛型T继承了自一个构造函数,这个构造函数,接受任意类型的数据组成的数组作为参数,这个构造函数返回任意类型的数据
- class extends constructor{}这里是对构造函数进行改写。这个改写的执行是在定义类的构造函数之后执行的。
- (constructor: T) 这里的意思是 constructor的类型就是一个泛型,这个泛型 T的意思是,可以通过实例化创建出一个类,这个类应该包含new (...args:any[]) => any这样的构造函数
经过上边的写法后,我们去通过test调用getName方法还是会报错,除非是 test as any才可以。原因是 我们定义类test的时候,并没有直接定义getName方法,而getName是testDecorator装饰器偷偷的装饰的时候加进来的,这个时候typescript是不知道加了这个方法的,要解决这个问题,需要工厂模式
。
function testDecoratorFactory() {
return function <T extends new (...args: any[]) => any>(constructor: T) {
// 这里改造的构造函数后执行
return class extends constructor{
name = 'lee';
getName() {
return this.name;
}
}
}
}
// 这个时候testDecoratorFactory不是当成一个装饰器来用,而是当成一个函数来用
// testDecoratorFactory()函数执行,返回一个装饰器
// 装饰器后边再跟(class {}),表示装饰器装饰的是一个没用名字的class,这个class就多出一个getName的方法了
// 修饰完成之后,把返回的东西复制给 Test
const Test = testDecoratorFactory()(class {
name: string;
constructor(name: string) {
this.name = name;
}
})
// 这里再去new 的Test是装饰器装饰过后的 class
// 所以实例 test就可以访问到getName了
const test = new Test('yang');
console.log(test.getName());