feng xiaohan

装饰器(Decorator)

用于给类、方法、属性等添加元数据或修改其行为,清晰地表达了意图,增加代码的可读性。

注意:装饰器是一种实验性的功能,需要启用实验性选项,并且它在未来版本可能会发生变化。

需要在 tsconfig.json 中打开装饰器语法:

"compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
}

类装饰器(ClassDecorator)

可以不去破坏原有类自身的结构,而给类添加新的属性或方法。(起一个修饰的作用)

const Base: ClassDecorator = (target) => {
  // target为Http的构造函数
  target.prototype.name = "张三";
  target.prototype.func = () => {
    console.log("我是新增加的方法");
  };
};

@Base // 装饰器用@修饰(加大写字母),它会自己去调用装饰器函数,不需要我们手动再去调用
class Http {
  // ...
}

const http = new Http() as any;
http.func();
http.name;

装饰器函数内会传递一个被装饰的类的构造函数(target),有了这个构造函数就可以不去破坏原有类自身的结构,而给类添加新的属性或方法。

  • target:构造函数

有的浏览器可能不支持@Base,可以使用它的底层原理来表示:

class Http {
  // ...
}
const http = new Http() as any;
Base(Http);
http.func();
http.name;

方法装饰器(MethodDecorator、PropertyDescriptor)

可以对某个方法进行封装,简化使用方法。

import axios from "axios";

const Get = (url: string) => {
  const fun: MethodDecorator = (
    target,
    key,
    descriptor: PropertyDescriptor
  ) => {
    axios.get(url).then((res) => {
      descriptor.value(res.data);
    });
  };
  return fun;
};

class Http {
  @Get("https://sdfdsf") // 定义方法装饰器,这样直接输入url地址就可以获得值
  getList(data: any) {
    // @Get里返回的值会自动传递到参数里
    console.log(data);
  }
}
  • target:原型对象
  • key:装饰的方法名
  • descriptor:描述符

参数装饰器(ParameterDecorator)

简化获取的参数。比如要获取的数据为 data.result.list,有了参数装饰器直接使用 data 就能获取到。

import "relect-metadata";
const Get = (url: string) => {
  const fun: MethodDecorator = (
    target,
    _key: any,
    descriptor: PropertyDescriptor
  ) => {
    const key = Reflect.getMetadata("key", target);
    axios.get(url).then((res) => {
      descriptor.value(key ? res.data[key] : res.data);
    });
  };
  return fun;
};

const Result = () => {
  const fun: ParameterDecorator = (target, key, index) => {
    Reflect.defineMetadata("key", "result", target);
  };
  return fun;
};

class Http {
  @Get("https://sdfdsf")
  getList(@Result() data: any) {
    // 定义参数装饰器
    console.log(data);
  }
}
  • @Result()比@Get()优先执行。
  • relect-metadata是一个存储、操作元数据的库。
  • target:原型对象
  • key:装饰的方法名
  • index:参数所在的位置

属性装饰器(PropertyDecorator)

const Name: PropertyDecorator = (target, key) => {
  console.log(target, key);
};

class Http {
  @Name
  xiaohan: string;
}
  • target:原型对象
  • key:属性名

装饰器工厂

利用函数柯里化,向装饰器传递参数,并且与装饰器函数内传递的参数区分。

const Base = (name: string) => {
  const fn: ClassDecorator = (target) => {
    target.prototype.name = name;
    target.prototype.func = () => {
      console.log("我是新增加的方法");
    };
  };
  return fn;
};

@Base("李四")
class Http {
  // ...
}

const http = new Http() as any;
console.log(http.name); // 李四