typescript-装饰器

537 阅读2分钟

1类的装饰器

  • 装饰器本身就是一个函数
  • 装饰器的参数是类的构造函数
  • 装饰器是对类本身进行修饰的函数,在类创建好之后立刻执行
  • 如果有两个装饰器,他会从下到上执行
function testDecorator(constructor:any){
    console.log('装饰器1')
    constructor.prototype.getName=()=>{
        console.log('ws')
    }
}
function testDecorator1(constructor:any){
    console.log('装饰器2')
    constructor.prototype.getName1=()=>{
        console.log('qy')
    }
}
@testDecorator
@testDecorator1
class Test{}

let test=new Test();
(test as any).getName()

1.1 工厂函数解决装饰器问题

这种写法可以做一个判断条件去使用装饰器

//装饰器条件
function waysDecorator(flag: boolean) {
  if (flag) {
    return function (constructor: any) {
      constructor.prototype.getName = () => {
        console.log("ws");
      };
    };
  } else {
    return function (constructor: any) {
      constructor.prototype.getName = () => {
        console.log("qy");
      };
    };
  }
}

//这里可以根据条件传递不同的参数从而改变我们所需要的装饰器
@waysDecorator(true)
class Ways {}

let ways = new Ways();
(ways as any).getName();

1.2装饰器装饰类

function wsDerator() {
    //这里使用一个泛型去继承构造器函数类型
  return function <T extends new (...arg: any[]) => any>(constructor: T) {
    return class extends constructor {
      name = "qy";
      getName() {
        return this.name;
      }
    };
  };
}

//用装饰器来修饰这个class
const Ws = wsDerator()(
  class {
    name: string;
    constructor(name: string) {
      this.name = name;
    }
  }
);
let ws=new Ws('ws')
ws.getName();
console.log(ws);

2.方法装饰器

  • 对于一个普通的方法装饰器taget对应的是类的prototype,key对应的是方法名
  • 创建好装饰器就会对类的方法进行装饰
  • 静态方法target对应的是类的构造函数
  • descriptor可以修改方法的属性,例如方法是否可以被重写,可以对原来的方法进行修改
function deratorGetname(target: any, key: string) {
//   console.log(target, key);
}
function deratorAge(target: any, key: string, descriptor:PropertyDescriptor) {
//   console.log(target, key,descriptor.value);
  descriptor.value= function(){
    return 37
  }
}
class West {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  @deratorGetname
  getName() {
    return this.name;
  }
  @deratorAge
  static getage() {
    return 26;
  }
}

const west = new West("ws");

3.访问器的装饰器

function deratorGet(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {
    console.log(target, key);
    descriptor.value=function(){
        return'qy'
    }
}


class Wast {
  private _name: string;
  constructor(name: string) {
    this._name = name;
  }
  @deratorGet
  get name() {
    return this._name;
  }
  set name(name: string) {
    this._name = name;
  }
}

const wast = new Wast("ws");

console.log(wast)

4.属性的装饰器

//这里修改的是原型上的name
function nameDeractor(target: any, key: string): any {
  target[key] = "ws";
}

class Person {
  @nameDeractor
  name: string;
  //这里的name是定义在类上的
  constructor(name: string) {
    this.name = name;
  }
}

let p1 = new Person("qy");
//这里访问根据原型链他会先找实例上的name
console.log(p1.name);
console.log((p1 as any).__proto__.name);

5.参数装饰器

//第一个参数是原型,第二个是参数名,第三个是参数位置
function paramsDecorator(target: any, key: string, index: number): any {
  console.log(target, key, index);
}

class Animal {
  getInfo(@paramsDecorator name: string, age: number) {
    console.log(name, age);
  }
}

let cat = new Animal();

cat.getInfo("xiaohua", 6);

6.装饰器用法

给每一个方法都包裹一个tr catch用于捕获错误

const tip: any = undefined;
//使用工厂模式包裹
function catchDecorator(msg: string) {
  return function (target: any, key: string, descriptor: PropertyDescriptor) {
    let fn = descriptor.value;
    descriptor.value = function () {
      try {
        fn();
      } catch (e) {
        console.log(msg);
      }
    };
  };
}
class Question {
  @catchDecorator("姓名不存在错误")
  getName() {
    return tip.name;
  }
  @catchDecorator("年龄不存在错误")
  getAge() {
    return tip.age;
  }
}

const q1 = new Question();
//这里会报错,需要给每个函数加上一个try catch捕获错误
q1.getName();
q1.getAge();