• WHAT - reflect-metadata


    一、介绍

    reflect-metadata 是一个JavaScript库,用于在运行时获取和操作JavaScript对象的元数据。它提供了一组装饰器(decorators)和一些辅助函数,用于在JavaScript类和成员上添加、读取和修改元数据。

    1.1 产生背景

    • Decorators add the ability to augment a class and its members as the class is defined, through a declarative syntax. 装饰器通过声明式语法,在定义类时为类及其成员提供了扩展的能力。
    • Traceur attaches annotations to a static property on the class. Traceur 将注解附加到类的静态属性上。
    • Languages like C# (.NET), and Java support attributes or annotations that add metadata to types, along with a reflective API for reading metadata. C# (.NET)Java 等编程语言支持属性或注解,可以向类型添加元数据,并提供反射API来读取元数据。

    1.2 目标

    • A number of use cases (Composition/Dependency Injection, Runtime Type Assertions, Reflection/Mirroring, Testing) want the ability to add additional metadata to a class in a consistent manner. 许多用例(组合/依赖注入、运行时类型断言、反射/镜像、测试)希望能够以一致的方式向类添加额外的元数据。
    • A consistent approach is needed for various tools and libraries to be able to reason over metadata. 需要一种一致的方法,使得各种工具和库能够对元数据进行推理。
    • Metadata-producing decorators (nee. “Annotations”) need to be generally composable with mutating decorators. 生成元数据的装饰器(原名“注解”)需要能够与修改装饰器进行一般化的组合。
    • Metadata should be available not only on an object but also through a Proxy, with related traps. 元数据不仅应该在对象上可用,还应该通过代理对象以及相关的 traps 进行访问。
    • Defining new metadata-producing decorators should not be arduous or over-complex for a developer. 对于开发人员来说,定义新的生成元数据的装饰器不应该是繁琐或过于复杂的。
    • Metadata should be consistent with other language and runtime features of ECMAScript. 元数据应该与ECMAScript的其他语言和运行时特性保持一致。

    1.2 主要功能

    1. 添加元数据:使用装饰器将元数据添加到类、方法、属性等上。例如,可以使用@Reflect.metadata()装饰器将元数据附加到一个类或方法上。
    class C {
      @Reflect.metadata(metadataKey, metadataValue)
      method() {
      }
    }
    
    // equals to
    // 自定义一个装饰器来添加元数据
    function MyMetadata(key: string, value: any) {
      return function(target: any, propertyKey: string) {
        Reflect.defineMetadata(key, value, target, propertyKey);
      };
    }
    
    1. 读取元数据:使用Reflect.getMetadata()函数读取已添加的元数据。可以通过提供元数据的键来获取相应的元数据值。
    let obj = new C();
    let metadataValue = Reflect.getMetadata(metadataKey, obj, "method");
    
    1. 修改元数据:使用Reflect.defineMetadata()函数修改已添加的元数据。可以通过提供元数据的键和新的元数据值来修改元数据。
    Reflect.defineMetadata(metadataKey, metadataValue, C.prototype, "method");
    

    完整实例:

    import 'reflect-metadata';
    
    // 定义一个类,并在其中的方法上添加元数据
    class MyClass {
      @Reflect.metadata('type', 'user')
      @Reflect.metadata('name', 'John')
      myMethod() {}
    }
    
    // 读取元数据
    const type = Reflect.getMetadata('type', MyClass.prototype, 'myMethod');
    const name = Reflect.getMetadata('name', MyClass.prototype, 'myMethod');
    
    console.log(type); // 'user'
    console.log(name); // 'John'
    

    通过使用reflect-metadata,可以在运行时动态地为对象添加附加信息,这对于一些需要在运行时进行元数据操作的场景非常有用,例如在依赖注入、==ORM(对象关系映射)==等方面。

    需要注意的是,reflect-metadata是一个第三方库,需要在项目中引入并使用。它在TypeScript中广泛使用,但也可以用于纯JavaScript项目中。

    二、对象的元数据

    在JavaScript中,元数据是指与对象相关的数据,可以包含关于对象的类型、属性、方法等的信息。元数据不是对象的属性或方法,而是与对象相关联的数据。通过使用reflect-metadata库,可以在运行时动态地操作和获取对象的元数据,而不需要依赖于静态的类型系统。

    元数据在JavaScript中通常使用对象属性的方式来实现。例如,可以使用以下方式添加和读取一个对象的元数据:

    // 添加元数据
    myObject.__metadata__ = {type: 'user', name: 'John'};
    
    // 读取元数据
    console.log(myObject.__metadata__.type); // 'user'
    console.log(myObject.__metadata__.name); // 'John'
    

    在ES6及更高版本中,可以使用Reflect对象的metadata方法来获取和设置对象的元数据。例如:

    // 添加元数据
    Reflect.defineMetadata('type', 'user', myObject);
    Reflect.defineMetadata('name', 'John', myObject);
    
    // 读取元数据
    console.log(Reflect.getMetadata('type', myObject)); // 'user'
    console.log(Reflect.getMetadata('name', myObject)); // 'John'
    

    需要注意的是,元数据不是JavaScript标准的一部分,而是一个非正式的概念。

    因此,需要使用第三方库(如reflect-metadata)来实现元数据的操作。同时,由于元数据不是JavaScript标准的一部分,因此它的使用方法和实现方式可能因库而异。

    三、场景:依赖注入

    import 'reflect-metadata';
    
    class Foo {}
    class Bar {}
    
    class MyService {
      constructor(
        @Inject('foo') private foo: Foo,
        @Inject('bar') private bar: Bar,
      ) {}
    }
    
    function Inject(key: string) {
      return function(target: any, propertyKey: string, parameterIndex: number) {
        const metadata = Reflect.getMetadata('design:paramtypes', target, propertyKey);
        metadata[parameterIndex] = { key };
        Reflect.defineMetadata('design:paramtypes', metadata, target, propertyKey);
      };
    }
    
    const myService = new MyService(new Foo(), new Bar());
    const metadata = Reflect.getMetadata('design:paramtypes', myService, undefined);
    console.log(metadata); // [ { key: 'foo' }, { key: 'bar' } ]
    

    上面的代码中,我们定义了一个 MyService 类,并在其构造函数中使用 @Inject() 装饰器添加了元数据。在 Inject() 装饰器中,我们使用 Reflect.getMetadata() 获取到函数参数的元数据,然后修改其中的元素,将 key 信息添加到其中,最后使用 Reflect.defineMetadata() 将修改后的元数据重新设置到函数参数上。最终,我们使用 Reflect.getMetadata() 来读取 MyService 实例的元数据,并打印出结果。

    四、场景:ORM(对象关系映射)

    import 'reflect-metadata';
    
    class User {
      @Column()
      id: number;
      @Column()
      name: string;
      @Column()
      age: number;
    }
    
    function Column() {
      return function(target: any, propertyKey: string) {
        const metadata = {
          type: Reflect.getMetadata('design:type', target, propertyKey),
          name: propertyKey,
        };
        Reflect.defineMetadata('column', metadata, target, propertyKey);
      };
    }
    
    const metadata = Reflect.getMetadata('column', User.prototype, 'id');
    console.log(metadata); // { type: Function, name: 'id' }
    
    

    上面的代码中,我们定义了一个 User 类,并在其属性上使用 @Column() 装饰器添加了元数据。在 Column() 装饰器中,我们使用 Reflect.getMetadata() 获取到属性类型的元数据以及属性名称,然后将其封装为一个对象,并使用 Reflect.defineMetadata() 将其设置到属性上。最终,我们使用 Reflect.getMetadata() 来读取 User 类的 id 属性的元数据,并打印出结果。

  • 相关阅读:
    C++入门(c++历史篇)
    Docker安装MySQL详细步骤
    Go中的一些优化笔记,简约而不简单
    【云原生】SQL(及存储过程)跑得太慢怎么办?
    【2017NOIP普及组】T1:成绩 试题解析
    docker swarm集群部署
    linux部署dagu和benthos作为调度平台+数据处理框架
    【JavaScript】巩固JS开发中五个常用功能/案例(46-50)(牛客题解)
    HTTP相关知识
    JavaEE——网络原理(网络层 IP协议与数据链路层)
  • 原文地址:https://blog.csdn.net/weixin_58540586/article/details/139473514