在之前那章 midwayjs路由实现那章 我们看到过这样的代码
/**
* save data to class
* @param decoratorNameKey
* @param data
* @param target
* @param mergeIfExist
*/
export function saveClassMetadata(
decoratorNameKey: ObjectIdentifier,
data: any,
target: any,
mergeIfExist?: boolean
) {
if (mergeIfExist && typeof data === 'object') {
const originData = manager.getMetadata(decoratorNameKey, target);
if (!originData) {
return manager.saveMetadata(decoratorNameKey, data, target);
}
if (Array.isArray(originData)) {
return manager.saveMetadata(
decoratorNameKey,
originData.concat(data),
target
);
} else {
return manager.saveMetadata(
decoratorNameKey,
Object.assign(originData, data),
target
);
}
} else {
return manager.saveMetadata(decoratorNameKey, data, target);
}
}
其中 manager 就是我们最开始所描述的容器 下面阶段来介绍下 这个 manager
1. saveMetadata
这个看方法名 理解起来也不难 就是 元数据的存储 接下来就是解析下 源码的执行过程
export class DecoratorManager extends Map implements IModuleStore {
/**
* the key for method meta data store in method
*/
injectMethodKeyPrefix = 'INJECTION_METHOD_META_DATA';
injectClassKeyPrefix = 'INJECTION_CLASS_META_DATA'
static getDecoratorMethodKey(decoratorNameKey: ObjectIdentifier) {
return decoratorNameKey.toString() + '_METHOD';
}
static getDecoratorMethod(
decoratorNameKey: ObjectIdentifier,
methodKey: ObjectIdentifier
) {
return (
DecoratorManager.getDecoratorMethodKey(decoratorNameKey) +
'_' +
methodKey.toString()
);
}
// 静态方法 存储元数据
static saveMetadata(
metaKey: string,
target: any,
dataKey: string,
data: any
) {
// filter Object.create(null)
if (typeof target === 'object' && target.constructor) {
target = target.constructor;
}
let m: Map<string, any>;
// 如果 target 对应的 元key 存在 元数据
if (Reflect.hasOwnMetadata(metaKey, target)) {
// m 等于用户存储的元数据
m = Reflect.getMetadata(metaKey, target);
} else {
// 否则 初始化一个新的 map
m = new Map<string, any>();
}
// 存储新的 属性值对应的数据
m.set(dataKey, data);
Reflect.defineMetadata(metaKey, m, target);
}
/**
* save meta data to class or property
* @param decoratorNameKey the alias name for decorator
* @param data the data you want to store
* @param target target class
* @param propertyName
*/
// 存储元数据
saveMetadata(
decoratorNameKey: ObjectIdentifier,
data,
target,
propertyName?
) {
if (propertyName) {
// 假如 用户输入了 propertyName
// saveMetadata('decoratorNameKey', {}, target, 'propertyKey')
const dataKey = DecoratorManager.getDecoratorMethod(
decoratorNameKey,
propertyName
);
// dataKey 此时取到的值 为 'decoratorNameKey_METHOD_propertyKey'
DecoratorManager.saveMetadata(
this.injectMethodKeyPrefix,
target,
dataKey,
data
);
} else {
// 如果用户没有输入 propertyName
// saveMetadata('decoratorNameKey', {}, target)
const dataKey = DecoratorManager.getDecoratorClassKey(decoratorNameKey);
// dataKey 此时取到的值 为 'decoratorNameKey_METHOD'
DecoratorManager.saveMetadata(
this.injectClassKeyPrefix,
target,
dataKey,
data
);
}
}
}
执行流程如下
- 首先 我们根据 有没有 propertyName 入参 来生成一个 dataKey
- 执行 DecoratorManager的静态方法 saveMetadata 来存储元数据
如果 没有 输入的 propertyName 的话 说明存储 的一个类级别的元数据 用 INJECTION_CLASS_META_DATA 所为 key
否则 的话 用 INJECTION_METHOD_META_DATA
同时看静态方法 也知道 这两个key 下存的值是 Map 的格式 而 Map 的key 就是我们刚才得出来的 dataKey
2. getMetadata
有set的话 就有get 那么继续看代码了
export class DecoratorManager extends Map implements IModuleStore {
// 静态方法 获取元数据
static getMetadata(metaKey: string, target: any, dataKey?: string) {
// filter Object.create(null)
if (typeof target === 'object' && target.constructor) {
target = target.constructor;
}
let m: Map<string, any>;
if (!Reflect.hasOwnMetadata(metaKey, target)) {
m = new Map<string, any>();
Reflect.defineMetadata(metaKey, m, target);
} else {
m = Reflect.getMetadata(metaKey, target);
}
if (!dataKey) {
return m;
}
return m.get(dataKey);
}
/**
* get single data from class or property
* @param decoratorNameKey
* @param target
* @param propertyName
*/
getMetadata(decoratorNameKey: ObjectIdentifier, target, propertyName?) {
if (propertyName) {
const dataKey = DecoratorManager.getDecoratorMethod(
decoratorNameKey,
propertyName
);
return DecoratorManager.getMetadata(
this.injectMethodKeyPrefix,
target,
dataKey
);
} else {
const dataKey = `${DecoratorManager.getDecoratorClassKey(
decoratorNameKey
)}`;
return DecoratorManager.getMetadata(
this.injectClassKeyPrefix,
target,
dataKey
);
}
}
}