typescript中的装饰器(笔记)

  • 装饰器是一种特殊类型的申明,它能够被附加到类申明、方法、属性或参数上,可以修改类的行为
  • 通俗的讲,装饰器就是一个方法,可以注入到类、方法、属性或参数上来扩展类、属性、方法、参数的功能
  • 常见的装饰器: 类装饰器、属性装饰器、方法装饰器、参数装饰器
  • 装饰器的写法: 普通装饰器(无法传参)、装饰器工厂(可以传参)

普通装饰器: 不能传参

 // 定义一个装饰器
function logClass(param:any){
    console.log(param)//输出:ƒ HttpClient() {}
    // 扩展类的属性与方法
    param.prototype.apiUrl="xxx"
    param.prototype.run=function(){
        console.log("动态扩展的run方法")
    }
}
@logClass
class HttpClient{
    constructor(){}
    getData(){

    }
}
let h:any = new HttpClient()
h.run()//动态扩展的run方法

装饰器工厂:可以传参

// 定义一个装饰器工厂
// param接收自己传的参数
// target接收类信息
function logClass(param:string){
    return function(target:any){
        console.log(param,target)//xxx ƒ HttpClient() {}
        // 属性扩展
        target.prototype.url = param
    }
}

@logClass("xxx")
class HttpClient{
    constructor(){}
    getData(){

    }
}

let h:any = new HttpClient()
console.log(h.url)//xxx

装饰器组合:多个装饰器可以同时应用到一个声明上,就像下面的示例:

//书写在同一行上:
@f @g x
//书写在多行上:
@f
@g
x

类装饰器:类装饰器在类声明之前被声明(紧靠着类声明),类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。

function decorObj(param:any) {
  console.log(param) // param就是createObj这个类
  return class extends param{
    name:any = '我是修改后的名字';
    getName() {
      console.log(this.name + '222222')
    }
  }
}

@decorObj
class createObj {
  public name:string | undefined;
  constructor(name:string) {
    this.name = name;
  }
  getName() {
    console.log(this.name)
  }
}
const obj = new createObj('张山');
obj.getName(); // 打印  我是修改后的名字222222
// 通过这个打印结构告诉我们,createObj的构造函数和getname这个方法都被修改了

方法装饰器:方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
  • 成员的属性描述符。
function getMethods(params:string) {
  return function(p1:any, p2:any, p3:any) {
    // console.log(p1) // 参数一:对于静态方法来说是类的构造函数,对于实例成员来说是原型对象prototype
    // console.log(p2) // 参数二:成员的名字
    // console.log(p3) // 参数三:成员的描述信息 
    let modifyMethods = p3.value; // p3.value就是createMethods中的modifyData这个方法
    p3.value = function (...args:any[]) { // 改写createMethods中的modifyData这个方法
      args = args.map(item => String(item)) // 强制将modifyData方法中的参数转换为string类型
      console.log(args)
      
      modifyMethods.apply(this, args) // 相当于在修改后的方法中又执行了原本的modifyData这个方法

    }
  }
}

class createMethods{
  public name:string | undefined
  constructor() {}
  @getMethods('123')
  modifyData(...args:any[]) { // 修改方法的时候,就在那个方法前面加一个装饰器
    console.log(args,'哈哈哈')
  }
  // @getMethods('456')
  getName() {
    console.log('111')
  }
}

const me = new createMethods();
me.modifyData('456',45454)

访问器装饰器:访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义。TypeScript不允许同时装饰一个成员的get和set访问器。访问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
  • 成员的属性描述符。
class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    @configurable(false)
    get x() { return this._x; }

    @configurable(false)
    get y() { return this._y; }
}
function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}

属性装饰器:属性装饰器声明在一个属性声明之前(紧靠着属性声明),属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
 function decorAttr(params:string) {
  console.log(params, 11);
  return function (target:any, attr:string) {
    console.log(target) // 注意这里target是CreateClass的prototype
    console.log(attr) // attr就是name 
    // 注意上面的name是在构造函数中初始化的,这里实在属性装饰器中初始化的
    target[attr] = params
  }
} 

class CreateClass {
  @decorAttr('通过属性装饰器给name初始化')
  public name:string | undefined;
  constructor(){}
  getName() {
    console.log(this.name);
  }
}
const obj = new CreateClass();
obj.getName()

参数装饰器:参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器只能用来监视一个方法的参数是否被传入,参数装饰器的返回值会被忽略。参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
  • 参数在函数参数列表中的索引。
// 方法参数装饰器
// 在执行方法时,调用方法参数装饰器,给类的原型对象增加属性,也可以修改参数
function logParams(param:any){
    return function(target:any,methodName:any,paramIndex:any){
        console.log(param,target,methodName,paramIndex)
         // 给原型对象增加属性
         target.id=param
    }
}

class HttpClient{
    url:string|undefined
    get(@logParams("uuid")uuid:any){
        console.log("类里面的实例方法"+uuid)
       
    }
}
let h:any = new HttpClient()
h.get(12233)//类里面的实例方法12233
console.log(h.id)//uuid

总结

装饰器可以对类、方法、属性、参数进行修改、扩展、替换等操作

执行顺序:属性装饰器->方法装饰器->方法参数装饰器->类装饰器

同类装饰器执行顺序:由下向上、由里及外、由后往前

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

the_lower

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值