Typescript - 装饰器

装饰器作用:

不修改类代码的基础上通过添加标注的方式来给代码添加功能,类的继承也是添加功能。

装饰器优点

  • 减少代码量
  • 提高代码扩展性、可读性和可维护性

装饰器环境:

   "experimentalDecorators": true,
类装饰器
装饰器格式
const moveDescript: ClassDecorator = (target: any) => {};

@moveDescript
//装饰器后面跟装饰器参数
class shenzhou {}

装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。记住是给类添加装饰,并不能在ts中给单独的函数或者熟悉添加功能。

类装饰器

装饰器语法糖

装饰器的写法是语法糖的表现形式

  class newClss {}
  buildHandler(newClss);
  moveBuild(newClss);
  const testClass = new newClss();
等价于
  @buildHandler
  @moveBuild

  class newClss {}
  // buildHandler(newClss);
  // moveBuild(newClss);
  const testClass = new newClss();

以上两种写法相等

装饰器叠加
const messageDescript: ClassDecorator = (target) => {
  target.prototype.message = function (msg) {
    console.log(msg);
  };
};
  const articleDescript = (target) => {
    target.prototype.article = function () {
      console.log('文章创建成功');
    };
  };

  @messageDescript
  @articleDescript
  class newClss {
    public login() {
      console.log('登录成功');
    }
  }

  const testClass = new newClss();
  (testClass as any).message('msg');
  (testClass as any).login();
  (testClass as any).article();
装饰器工厂

以买车为例,4S店可以根据用户的需求选配,在工厂进行生产。

装饰器工厂类似,根据不同的场景需求返回不同的装饰器,这样的函数,我们称为装饰器工厂。

  const musicDescript = (path: number): ClassDecorator => {
    switch (path) {
      case 1:
        return (target) => {
          target.prototype.player = () => {
            console.log('游戏开始了');
          };
        };
        break;
      case 2:
        return (target) => {
          target.prototype.player = () => {
            console.log('表演开始了');
          };
        };
    }
  };
  @musicDescript(2)
  class newClss {
    public login() {
      console.log('登录成功');
    }
  }
  const testClass = new newClss();

  (testClass as any).player();

方法装饰器

给类中的可继承属性&方法(原型对象上的属性&方法)添加装饰器

方法装饰器共有三个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

  2. 成员的名字。

  3. 成员的属性描述符

    descriptor必须给到参数类型,否则会报错。

   const methodHandler = (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) => {
    descriptor.value = () => {
      console.log('挂载成功');
    };
  };
 
 class build {
    @methodHandler
    public clickHander() {
      const age = 18;
      console.log(age);
    }
  }
  const newBuild = new build();
  (newBuild as any).clickHander();

给静态属性(构造函数上的属性和方法 eg:Array.from())添加装饰器

  const methodHandler = (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) => {
    descriptor.value = () => {
      console.log('挂载成功');
    };
  };

  await app.listen(3000);
  class build {
    @methodHandler
    static clickHander() {
      const age = 18;
      console.log(age);
    }
  }

  build.clickHander();
异步方法装饰器案例
  const methodAsyncHandler = (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) => {
    const value = descriptor.value;
    descriptor.value = async () => {
      setTimeout(() => {
        value();
      }, 2000);
    };
  };
  class build {
    @methodAsyncHandler
    static async clickHander() {
      // return 18;
      console.log(10);
    }
  }
  build.clickHander();
方法装饰器工厂
 const methodAsyncHandler = (path): MethodDecorator => {
    return function (
      target: any,
      propertyKey: string,
      descriptor: PropertyDescriptor,
    ) {
      descriptor.value = function (): any {
        console.log(path);
      };
    };
  };
  await app.listen(3000);
  class build {
    @methodAsyncHandler('path')
    static async clickHander() {
      console.log('异步装饰器');
    }
  }
  build.clickHander();
装饰器自定义console.log
  const methodAsyncHandler = (message): MethodDecorator => {
    return function (
      target: any,
      propertyKey: string,
      descriptor: PropertyDescriptor,
    ) {
      const method = descriptor.value;
      descriptor.value = function (): any {
        try {
          method();
        } catch (error: any) {
          // throw error;
          console.log(message);
        }
      };
    };
  };

  class build {
    @methodAsyncHandler('错误信息')
    findHander() {
      throw new Error('报错了');
    }
  }
  const funny = new build();
  funny.findHander();
属性装饰器和参数装饰器
参数选择器

装饰器表达式会在运行时当作函数被调用,传入下列3个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。(装饰的是静态属性,则该参数是构造函数,若装饰的是动态属性,则该参数是实例化的对象)
  2. 成员的名字。(装饰的方法名)
  3. 参数在函数参数列表中的索引
属性装饰器

装饰器表达式会在运行时当作函数被调用,传入下列2个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  // 参数装饰器
  const parameterDescript: ParameterDecorator = (
    target: any,
    propertyKey: string | symbol,
    parameterIndex: number,
  ) => {
    console.log(target, propertyKey, parameterIndex);
  };
  // 属性装饰器
  const propertyDescript: PropertyDecorator = (
    target: any,
    propertyKey: string,
  ) => {
    console.log(propertyKey, target);
  };
  await app.listen(3000);
  class build {
    @propertyDescript
    public distance = 1000;
    clickHander(@parameterDescript info: string, id: number) {
      console.log(info, id);
    }
  }
  const funny = new build();
  funny.clickHander('小林', 18);
属性装饰器案例
  const properDescript = (): PropertyDecorator => {
    return (target: Object, propertyKey: string | symbol) => {
      Object.defineProperty(target, propertyKey, {
        get() {
          return '马化腾';
        },
      });
    };
  };

  class properClass {
    @properDescript()
    public name: string | any;
  }
  let textCon = new properClass();
  console.log(textCon.name);

元数据

元数据指数据的数据,可以给某个对象的数据添加额外的描述。

它可以用来描述 对象,这些用来描述数据的数据就是 元数据

比如一首歌曲本身就是一组数据,同时还有一组用来描述歌曲的歌手、格式、时长的数据,那么这组数据就是歌曲数据的元数据

元数据使用案例

const methodDescripts: MethodDecorator = (
  target: any,
  propertyKey: string | symbol,
  descriptor: PropertyDescriptor
) => {
  console.log(Reflect.getMetadata("require", target));
};
let keyArr: any = [];
const paramsDescript: ParameterDecorator = (
  target: any,
  propertyKey: string | symbol,
  parameterIndex: number
) => {
  keyArr.push(parameterIndex);
  Reflect.defineMetadata("require", keyArr, target);
};
class User {
  @methodDescripts
  find(@paramsDescript id: number, @paramsDescript name: string) {
    console.log(id);
  }
}
元数据使用的简单案例
@Reflect.metadata("n", "这是一个优质的装饰器")
class User {
  @methodDescripts
  find(@paramsDescript id: number, @paramsDescript name: string) {
    console.log(id);
  }
}
console.log(Reflect.getMetadata("n", User));
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值