一、类的装饰器
①package.json中添加dev命令
"dev": "ts-node ./src/index.ts"
②tsconfig.json中把实验类型的支持打开
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
③使用多个装饰器,从上到下(从左到右)收集装饰器,从下到上(从右到左)执行装饰器
//类的装饰器
//装饰器本身是一个函数
//类装饰器接受的参数是构造函数
//装饰器通过 @ 符号来使用
function testDecorator(constructor: any) {
// constructor.prototype.getName = () => {
// console.log('dell');
// }
console.log('decorator');
}
function testDecorator1(constructor: any) {
console.log('decorator1');
}
//装饰器会在类创建好之后立即执行,对类做一些装饰
@testDecorator
@testDecorator1
class Test {}
const test = new Test();
// (test as any).getName();
④定义函数,使用工厂模式返回装饰器,使得在满足一定条件后才会执行装饰器
function testDecorator(flag: boolean){
if(flag) {
return function (constructor: any) {
constructor.prototype.getName = () => {
console.log('dell');
}
}
}else{
return function (constructor: any) {};
}
}
@testDecorator(true)
class Test {}
const test = new Test();
(test as any).getName();
⑤constructor类型由any类型改为定义为泛型T
// new后面是一个构造函数,接收很多参数,每一个参数的类型是any,返回的是一个any类型的内容
// T 类型可以被这个构造函数实例化出来
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('dell');
console.log((test as any).getName())
⑥解决test无法直接调用getName —— test.getName()会报错
function testDecorator() {
return function<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
name = 'lee';
getName() {
return this.name;
}
};
};
}
//执行结果返回的装饰器,修饰class
const Test = testDecorator()(class {
name: string;
constructor(name: string) {
this.name = name;
}
})
const test = new Test('dell');
console.log(test.getName())
二、方法装饰器
//装饰器 永远都是一个函数
//普通方法, target对应的是类的prototype
//静态方法,target对应的是类的构造函数
//和Object.defineProperty类似
//Object.defineProperty(obj, prop, descriptor)
//参数:原型对象,属性,(descriptor保存着)控制函数的一些属性
function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
//允许修改原始方法
// descriptor.writable = true;
//修改原始方法的值
descriptor.value = function () {
return 'decorator';
}
}
class Test {
name: string;
constructor(name: string) {
this.name = name;
}
@getNameDecorator
getName() {
return this.name;
}
}
const test = new Test('dell');
// test.getName = () => {
// return '123';
// }
console.log(test.getName());
三、访问器的装饰器
function visitDecorator(target: any, key: string, descriptor: PropertyDescriptor){
// 访问器不允许重写修改
// descriptor.writable = false;
}
class Test {
private _name: string;
constructor(name: string) {
this._name = name;
}
//Getter 访问器
get name() {
return this._name;
}
@visitDecorator
set name(name: string) {
this._name = name;
}
}
const test = new Test('dell');
test.name = '123123123123';
console.log(test.name);
四、属性的装饰器
// function nameDecorator(target: any, key: string): any{
// const descriptor: PropertyDescriptor = {
// writable: false
// };
// return descriptor; //会替换掉name属性的descriptor
// }
//修改的并不是实例上的name,而是原型上的name
function nameDecorator(target: any, key: string): any{
target[key] = 'lee';
}
//name 放在实例上
class Test {
@nameDecorator
name = 'Dell';
}
const test = new Test();
// test.name = 'dell lee';
// console.log(test.name); // Dell
console.log((test as any).__proto__.name); // lee
五、参数装饰器
// 原型, 方法名, 参数所在的位置
function paramDecorator(target: any, method: string, paramIndex: number){
console.log(target, method, paramIndex)
}
class Test {
getInfo( name: string, @paramDecorator age: number) {
console.log(name, age);
}
}
const test = new Test();
test.getInfo('Dell', 30);
六、装饰器实际使用的小例子
const userInfo: any = undefined;
//工厂模式写方法装饰器,解决代码复用中方法不同打印结果不同
function catchError(msg: string) {
return function (target: any, key: string, descriptor: PropertyDescriptor){
const fn = descriptor.value;
descriptor.value = function() {
try {
fn();
}catch(e) {
console.log(msg)
}
}
}
}
class Test {
@catchError('userInfo.name不存在')
getName() {
// try{
// return userInfo.name
// }catch(e) {
// console.log('userInfo.name 不存在')
// }
return userInfo.name
}
@catchError('userInfo.age不存在')
getAge() {
// try{
// return userInfo.age
// }catch(e) {
// console.log('userInfo.age 不存在')
// }
return userInfo.age
}
}
const test = new Test();
test.getName();
test.getAge();
注:课程源自慕课网