阅读 179

元数据编程 -- Reflect 与 metadata

前一篇文章介绍了 Reflect 基础 API 的内容,使用 Reflect 可以为对象设置属性,这个属性是会被直接添加到对象上的,有时候我们需要添加一种元数据,这种数据是用来描述对象本身,不应该出现在对象上。基于这种需求,有一个关于 metadata 的提案,这个提案在 Reflect 对象上扩展了元数据的能力。元数据是对反射功能的一个补充,在一些框架开发场景下很有用,由于这个功能还没有stable,我们可以引入 reflect-metadata 库来使用元数据能力。

meta-data 提案中包含以下方法:

  • Reflect.defineMetadata

  • Reflect.hasMetadata

  • Reflect.hasOwnMetadata

  • Reflect.getMetadata

  • Reflect.getOwnMetadata

  • Reflect.getMetadataKeys

  • Reflect.deleteMetadata

从方法名可以看出他们的作用,和常规的数据定义方法名风格是一致的,只是这里定义的是元数据信息元数据不影响程序运行,只能使用元数据相关 API 可以操控元数据。

查看 meta-data 源码可以看到实际上内部是利用一个 WeakMap 来实现的,元数据被存储在一个独立的 WeakMap 中,这样不影响程序本身,只在想获取时去读取即可。这里利用了 map 的数据结构可以接收对象作为 key 的特点。

除了之前提到的方法,Reflect 中还提供了一个装饰器,使用 @Reflect.metadata(metadataKey, metadataValue) 可以直接添加元数据,结合装饰器可以更容易进行元数据编程。使用 @Reflect.metadata 装饰器,我们可以很方便的对一个类的成员方法进行标识:

// Design-time type annotations function Type(type) { return Reflect.metadata("design:type", type); } function ParamTypes(...types) { return Reflect.metadata("design:paramtypes", types); } function ReturnType(type) { return Reflect.metadata("design:returntype", type); } // Decorator application @ParamTypes(String, Number) class C {   constructor(text, i) {   }   @Type(String)   get name() { return "text"; }   @Type(Function)   @ParamTypes(Number, Number)   @ReturnType(Number)   add(x, y) {     return x + y;   } }  复制代码

这样通过 Reflect.getMetadata 就可以获取到标识的字段类型、参数类型、返回值类型。

在 typescript 中,编译器可以为我们自动添加上面的三种元数据类型:只需要在 tsconfig 文件中设置 emitDecoratorMetadata 值为 true 即可:

// typescript class Demo {   @LogMethod   public foo(bar: number) {     // do nothing   } } // without emitDecoratorMetadata class Demo {     foo(bar) {         // do nothing     } } __decorate([     LogMethod ], Demo.prototype, "foo", null); // with emitDecoratorMetadata class Demo {     foo(bar) {         // do nothing     } } __decorate([     LogMethod,     __metadata("design:type", Function),     __metadata("design:paramtypes", [Number]),     __metadata("design:returntype", void 0) ], Demo.prototype, "foo", null); 复制代码

可以看到当开启 emitDecoratorMetadata 时,在装饰器中会自动添加 design:type、design:paramtypes、design:returntype 三种类型的元数据信息,我们可以通过 Reflect.getMetadata 直接获取相关的类型信息。

元数据编程多用于框架开发,有时需要实现动态加载,或者需要添加一些标识信息,这些场景通常会使用元数据来实现,开源框架 InversifyJS、angular、nest 中都有使用。

最后还是要注意这个提案还没进入标准,目前使用的是 reflect-metadata 库的实现版本,可能以后相关的 API 会有变化。

 伪原创工具 SEO网站优化  https://www.237it.com/ 

作者:丨隋堤倦客丨
链接:https://juejin.cn/post/7035598935225794573


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐