ts装饰器

什么是装饰器

官方解释: 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
个人理解: 装饰,自然是为了起辅助作用,例如你做了一个程序,但是这个程序不满足你的要求,你想修改或者增添一些功能,这个时候我们就可以用到装饰器。

环境搭建

  1. 首先要跑ts代码的话,得先安装typescript
npm install typescript -g

在根目录下输入tsc命令,如果没报错代表安装成功。

  1. 创建tsconfig文件,根目录下就会生成tsconfig.json文件
tsc --init

在这里插入图片描述
3. 接着在tsconfig.json文件搜索 decorator,如下图,解开文件中的注释,接下来你就可以愉快的开发了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/9aa5257dfd1b41d7902af8af18468182.png

  1. 执行代码
  • 监控对应的文件夹下的文件,执行该命令后会生成对应的js文件
tsc -w
  • 执行对应的js文件,index.js是对应的文件名,注意这里要看终端的目录是否正确
node index.js

装饰器类型

装饰器的本质就是一个函数,根据装饰器修饰的值的不同,将装饰器进行了分类。修饰什么类型的值就就是什么装饰器。

类装饰器

类装饰器比较简单,我们来简单看个例子。

const MessageDecorator: ClassDecorator = (target: Function) => {
  target.prototype.message = (context:string) => {
    console.log(context);
  }
}
@MessageDecorator
class LoginController {
    public login () {
        console.log('登入业务处理');
        console.log('登入成功消息');
        (this as any).message('恭喜登入成功'); 
    }
}
new LoginController().login();

类装饰器只有一个参数target,他是一个构造函数,该装饰器在原型上加了一个message方法,所以类中可以直接调用。

方法装饰器

接下来,我们依旧看一段代码来讲解方法装饰器,这是多种代码的组合,可能会报错,主要是讲解其中的知识点。

const showDecorator: MethodDecorator = (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    target.name = 'zs';
    descriptor.value = () => {
        console.log('后盾人');
    }
    descriptor.writable = false;
}
class User {
    // 方法装饰器:如果是修饰普通方法,则args[0]是原型对象,如果修饰的是静态方法,则args[0]是构造函数
    @showDecorator
    public  static show() {
       console.log('houdunren.com');
    };
}
// console.log(new User().name);
// new User().show(); 
User.show = () => {
  console.log("12"); 
}

方法装饰器有三个参数,
第一个参数target: 如果是修饰普通方法,则target代表的是原型对象,如果修饰的是静态方法(static),target则是一个构造函数。
第二个参数propertyKey: 是函数的名字,例如这里则是 ‘show’
第三个参数descriptor: 主要是函数的一些配置属性,这里介绍2个比较常用的
descriptor.value // 可以获取到该函数
descriptor.writable // 控制该函数是否可以修改

属性装饰器
const VisitDecorator:PropertyDecorator = (target: Object, propertyKey: string | symbol) => {
    let value: string | undefined;
    Object.defineProperty(target,propertyKey,{
      get: () => {
        return value?.toLowerCase();
      },
      set: (v:string) => {
         value = v;
      }
    })
  }
  class Visit {
    @VisitDecorator
    title: string | undefined
  }
  const obj = new Visit();
  obj.title = 'JEKS;FKSLFSFS';
  console.log(obj.title);

第一个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
第二个参数: 成员的名字。
该代码也比较简单,在装饰器中对title属性进行拦截,将大写字母转化成小写。

参数装饰器
const RequiredDecorator: ParameterDecorator = function(target:any,propertyKey:string | symbol,parameterIndex:number) {
    let requiredParams: number[] = [];
    requiredParams.push(parameterIndex);
}
class ValidateUser {
  find(name:string,@RequiredDecorator id:number) {
    console.log(id);
  }
}

参数装饰器的的前两个参数和方法装饰器相同,第三个参数代表的是被装饰器修饰的参数,在函数中的位置索引,例如此处parameterIndex则为1,find函数中装饰器修饰的id的位置索引为1

装饰器番外

装饰器工厂

装饰器工厂本质就是一个高阶函数,让装饰器可以传递参数,接下来我用一个延时函数来了解下

const sleepDecoratorFactory = (waitTime:number) => (target:any,propertyKey:string | symbol,descriptor:PropertyDescriptor) => {
        target.name = 'zs';
        const value = descriptor.value;
        descriptor.value = () => {
          setTimeout(() => {
              value();  
          },waitTime)
        }
}
class Music {
    @sleepDecoratorFactory(2000)
    public play() {
        console.log("start play");  
    }
}
new Music().play();
console.log((new Music() as any).name);
元数据

对于数据的描述,接下来我们看看怎么使用

  1. 安装依赖
npm i reflect-metadata --save
import 'reflect-metadata';
const RequiredDecorator: ParameterDecorator = function(target:any,propertyKey:string | symbol,parameterIndex:number) {
    let requiredParams: number[] = [];
    requiredParams.push(parameterIndex);
    Reflect.defineMetadata('required',requiredParams,target,propertyKey)
}
const validateDecorator: MethodDecorator = (target:any,propertyKey: string | symbol,descriptor:PropertyDescriptor) => {
    console.log(Reflect.getMetadata('required',target,propertyKey));
    const method = descriptor.value;
    descriptor.value = function() {
       const requiredParams:number[] =  Reflect.getMetadata('required',target,propertyKey) || [];
       requiredParams.forEach(index => {
        if (index > arguments.length || arguments[index] === undefined) {
            throw new Error('请传递必要参数')
        } else {
            method.apply(this,arguments) 
        }
       })
    }
}
class ValidateUser {
  @validateDecorator
  find(name:string,@RequiredDecorator id:number) {
    console.log(id);
  }
}
new ValidateUser().find('zs',1)

Reflect.defineMetadata(‘required’,requiredParams,target,propertyKey);
第一个参数,相当于获取数据的唯一key,
第二个参数,对于数据的描述数据,
第三个参数,对象
第四个参数,对象中的具体属性
Reflect.getMetadata(‘required’,target,propertyKey),通过可以可以获取到requiredParams,之前defineMetadata中存储的数据

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值