前言: 本类文章初衷只用作记录个人的学习博客,哪里有漏补哪里,不做任何其他商业用途。欢迎讨论,不喜勿喷。后面要是有遗漏的相关知识点,也会相应的补上。如果本篇文章能帮到你,我也会很愉快,共勉😁
本篇文章有需要用到ts的前置知识装饰器(Decorator),如果有不太了解的可以参考【查漏补缺系列-ts篇】装饰器
目录
- 什么是元数据
- 编译环境
- 语法
- API
什么是元数据
元数据,简单定义就是描述数据的数据。只要有一类事物存在的地方,就有其对应元数据。举个栗子:一个人看起来二十岁左右(年龄)、个子高挑(身高)、红红的脸蛋,精致的五官(相貌),每天都非常活跃、朝气十足(性格)。
这个栗子中的年龄、身高、相貌、性格就是元数据,因为它们是用来描述具体数据/信息的数据/信息。在我们的程序中,它可以用来描述对象、类,这些用来描述数据的数据就是元数据。
ts中的元数据
通过给类、方法等指定或定义其进一步的属性来丰富它的形态。元数据的使用范围通常会被附加到指定的对象、类、方法上。具体实现有以下几点:
- 拓展已有的属性形态
- 不改变影响对象、类、方法本身的代码
- 统一对象的操作
元数据目前是由reflect-metadata库提供实现。
要在 TypeScript 项目中启用对装饰器和元数据的支持,需将"experimentalDecorators": true和"emitDecoratorMetadata": true添加到tsconfig.json中。
编译环境
全局安装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
通过装饰器来为类、实例方法和静态方法分别设置对应的元数据,ClassDecorator和MethodDecorator是reflect-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