【查漏补缺系列-ts篇】元数据

71 阅读4分钟

前言: 本类文章初衷只用作记录个人的学习博客,哪里有漏补哪里,不做任何其他商业用途。欢迎讨论,不喜勿喷。后面要是有遗漏的相关知识点,也会相应的补上。如果本篇文章能帮到你,我也会很愉快,共勉😁

本篇文章有需要用到ts的前置知识装饰器(Decorator),如果有不太了解的可以参考【查漏补缺系列-ts篇】装饰器

目录

  1. 什么是元数据
  2. 编译环境
  3. 语法
  4. API

什么是元数据

元数据,简单定义就是描述数据的数据。只要有一类事物存在的地方,就有其对应元数据。举个栗子:一个人看起来二十岁左右(年龄)、个子高挑(身高)、红红的脸蛋,精致的五官(相貌),每天都非常活跃、朝气十足(性格)。

这个栗子中的年龄身高相貌性格就是元数据,因为它们是用来描述具体数据/信息的数据/信息。在我们的程序中,它可以用来描述对象、类,这些用来描述数据的数据就是元数据

ts中的元数据

通过给类、方法等指定或定义其进一步的属性来丰富它的形态。元数据的使用范围通常会被附加到指定的对象、类、方法上。具体实现有以下几点:

  1. 拓展已有的属性形态
  2. 不改变影响对象、类、方法本身的代码
  3. 统一对象的操作

元数据目前是由reflect-metadata库提供实现。

要在 TypeScript 项目中启用对装饰器和元数据的支持,需将"experimentalDecorators": true"emitDecoratorMetadata": true添加到tsconfig.json中。

reflect-metadata文档地址

编译环境

全局安装Typescript:

  • npm install typescript -g

全局安装ts的编译工具

  • npm install ts-node -g

安装reflect-metadata

  • npm init
  • npm install reflect-metadata --save

ts-node xxx.ts运行ts文件

在目录下新建tsconfig.json,并写入:

{
  "compilerOptions": {
      "target": "ES5",
      "experimentalDecorators": true, // 开启ts装饰器
      "emitDecoratorMetadata": true // 开启reflect-metadata
  }
}

语法

基本语法

import 'reflect-metadata'

class Gretter {
  init() { }
}

Reflect.defineMetadata('gretter', 'GretterValue', Gretter)
Reflect.defineMetadata('gretter', 'GretterInitValue', Gretter, 'init')

console.log(Reflect.getMetadata('gretter', Gretter)) // GretterValue
console.log(Reflect.getMetadata('gretter', Gretter, 'test')) // GretterInitValue

Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey?)用以设置元数据

  • metadataKey:元数据的key
  • metadataValue:元数据的value
  • target:元数据要附加的目标对象
  • propertyKey:对应的属性key

getMetadata(metadataKey, target, propertyKey?)用以获取指定元数据

装饰器写法(命令式定义)

import 'reflect-metadata'

function ClassDecorator(): ClassDecorator {
  return constructor => Reflect.defineMetadata('gretter', 'classValue', constructor)
}

function MethodDecorator(): MethodDecorator {
  return (constructor, key, descriptor) => Reflect.defineMetadata('gretter', 'methodValue', constructor, key)
}

function StaticMethodDecorator(): MethodDecorator {
  return (constructor, key, descriptor) => Reflect.defineMetadata('gretter', 'staticMethodValue', constructor, key)
}
@ClassDecorator()
class Gretter {
  @MethodDecorator()
  public instMethod() { }

  @StaticMethodDecorator()
  public static staticMethod() {}

}

const install = new Gretter()

console.log(Reflect.getMetadata('gretter', Gretter)) // classValue
console.log(Reflect.getMetadata('gretter', install, 'instMethod')) // methodValue
console.log(Reflect.getMetadata('gretter', Gretter, 'staticMethod')) // staticMethodValue

通过装饰器来为类、实例方法和静态方法分别设置对应的元数据,ClassDecoratorMethodDecoratorreflect-metadata中提供的ts类型。

这里需要注意的是实例方法instaMethod的目标对象是实例化后的实例对象,不要写成类Gretter了(当时获取instaMethod的这个元数据时,一直是undefined,这坑找了好一阵😭😭😭)。

装饰器写法(声明式定义)

import 'reflect-metadata'
@Reflect.metadata('gretter', 'classValue')
class Gretter {
  @Reflect.metadata('gretter', 'methodValue')
  public instMethod() { }

  @Reflect.metadata('gretter', 'staticMethodValue')
  public static staticMethod() {}

}

const install = new Gretter()

console.log(Reflect.getMetadata('gretter', Gretter)) // classValue
console.log(Reflect.getMetadata('gretter', install, 'instMethod')) // methodValue
console.log(Reflect.getMetadata('gretter', Gretter, 'staticMethod')) // staticMethodValue

声明式写法则是直接使用reflect-metadata提供的Reflect.metadata(metadataKey, metadataValue)来声明元数据的定义。这两种写法从结果上来说没有任何区别,可以根据自己的业务场景决定使用哪一种。

API

参数:

  • metadataKey:元数据的key
  • metadataValue:元数据的value
  • target:元数据要附加的目标对象
  • propertyKey:对应的属性key

metadata

Reflect.metadata(metadataKey, metadataValue) 通过装饰器将元数据应用于构造函数。

@Reflect.metadata('gretter', 'classValue')
class Gretter {
  @Reflect.metadata('gretter', 'methodValue')
  public instMethod() { }

  @Reflect.metadata('gretter', 'staticMethodValue')
  public static staticMethod() {}
}

defineMetadata

Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey?)设置metadata(上面章节已介绍过)。

getMetadata

getMetadata(metadataKey, target, propertyKey?)获取对象或属性的原型链上的元数据键的metadataValue(上面章节已介绍过)。

hasMetadata

Reflect.hasMetadata(metadataKey, target, propertyKey?)检查对象或属性的原型链上是否存在metadataKey

Reflect.hasMetadata('gretter', Gretter) // true

hasOwnMetadata

Reflect.hasOwnMetadata(metadataKey, target, propertyKey)检查对象或属性是否存在自己的metadataKey

Reflect.hasOwnMetadata('gretter', Gretter, 'staticMethod') // true

getOwnMetadata

Reflect.getOwnMetadata(metadataKey, target, propertyKey)获取对象或属性的元数据键的metadataKey

Reflect.getOwnMetadata('gretter', Gretter, 'staticMethod') // staticMethodValue

deleteMetadata

Reflect.deleteMetadata(metadataKey, target, propertyKey)从对象或属性中删除metadata

Reflect.deleteMetadata('gretter', Gretter, 'staticMethod')
console.log(Reflect.getMetadata('gretter', Gretter, 'staticMethod')) // undefined