类装饰器
-
装饰器本身是一个函数,是在类创建的时候执行,传递给装饰器的函数的参数是构造函数
function testDecoration2(constructor: any) { // 这样可以扩展构造函数的方法 constructor.prototype.getName = () => { console.info('hello'); } console.info('testDecoration2'); } function testDecoration2(constructor: any) { console.info('testDecoration2'); } // 如果存在多个装饰器 下面的装饰器会被先执行 @testDecoration(true) @testDecoration2 class Test { }
-
上面的例子装饰器的类型是any,不是很规范
// 接受一个any类型的数组参数返回一个any,new关键字表示可以实例化为构造函数, T就是一个可以实例化的类或者是构造函数 function testDecoration< T extends new (...args: any[]) => any>(constructor: T) { console.info(constructor); // class继承的函数必须是构造函数,这个时候就相当于继承类,会先执行父类的构造函数然后执行子类的,也就是说 这个时候name是xin //  所以这个时候的T也是一样的道理 继承了构造函数 return class extends constructor{ name = 'xin'; getName() { return this.name; } } } @testDecoration class Test { name: string; constructor (name: string) { console.info('父类') this.name = name; } } const test = new Test ('kai'); // 会报错,TS不知道装饰器已经有了getName 所以会报错 必须As console.info((test as any).getName());
-
使用工厂方式解决getName报错问题
function testDecoration() { return function < T extends new (...args: any[]) => any>(constructor: T) { return class extends constructor{ name = 'xin'; getName() { return this.name; } } } } const Test = testDecoration5()( class { name: string; constructor (name: string) { this.name = name; } }); const test= new Test ('kai'); // 不会报错 test 拿到的是已经装饰过后的类 所以可以识别getName console.info(test.getName());
方法的装饰器
-
普通的方法装饰器
// 普通方法 target对应类的prtotype, key是装饰的方法的名字, descriptor就是函数的属性的控制 // 静态方法 target对应的是类的构造函数 function functionDecorator (target: any, key: string, descriptor: PropertyDescriptor ) { // 可以被重写 descriptor.writable = true; // 对方法进行变更,getName就变了 descriptor.value = function () { return 'test descriptor'; } } class Test{ name: string; constructor (name: string) { this.name = name; } // 在类创建的时候 就会对类的方法进行装饰 @functionDecorator getName() { return this.name } } const test = new Test('paul'); test.getName = () => { return 'test getName'; } // 输出test descriptor console.info(test.getName());
-
捕获异常装饰器
function catchError(target:any, keys: string, descriptor: PropertyDescriptor) { const fn = descriptor.value; descriptor.value = function () { try{ fn() } catch(e) { console.log('异常 属性不存在'); } } } const userInfo: any = undefined; class Test { @catchError getName() { return userInfo.name; } @catchError getAge() { return userInfo.age; } } const test = new Test(); test.getName();
访问器的装饰器
// getter和setter不能使用同一装饰器
function functionDecorator (target: any, key: string, descriptor: PropertyDescriptor ) {
descriptor.writable = false;
}
class Test{
private _name: string;
constructor (name: string) {
this._name = name;
}
// 在类创建的时候 就会对类的方法进行装饰
get name () {
return this._name
}
@functionDecorator
set name(name: string) {
this._name = name;
}
}
const test = new Test('paul');
// 会报错,因为不可修改
test.name = 'test';
console.info(test.name);
属性装饰器
// target是class的原型
function propxDecorator (target: any, key: string): any {
// 修改原型的属性值
target[key] = 'test desc';
// 返回的新的 会替换老的descriptor
const descriptor: PropertyDescriptor = {
writable: false
}
return descriptor;
}
class Test{
@propxDecorator
name: string;
constructor (name: string) {
this.name = name;
}
}
const test = new Test('paul');
// 会报错 只读的 不能写
test.name = 'xin';
console.info(test.name);
参数装饰器
// target是class的原型
function paramDecorator (target: any, key: string, paramIndex: number) {
// 0
console.info(paramIndex);
}
class Test{
getName(@paramDecorator name: string) {
return name;
}
}
const test = new Test();
console.info(test.getName('11'));
装饰器执行顺序
- 方法装饰器>类装饰器