前端发展很快,新鲜的工具、框架,甚至语言层出不穷。这虽然提高了开发效率和项目质量,但是从某种程度上来说也让学习曲线变的陡峭了一点。
在不少ts项目里边看到了类似java项目里边那样依赖注解,给对象或者属性添加额外描述信息的写法,觉得还是挺方便的,恰好今天看到一个项目里边提到了这个东西实现基于的技术,就学习翻译一下它的文档吧。
首先这个这个元数据还是一个提案,各种运行环境里边暂时都还没支持,但是因其强大的特性,社区已经开始用起来了。要用到这个特性,首先需要安装 reflect-metadata模块,这个模块会向全局的Reflect里边注入metadata相关的反射操作。
npm install reflect-metadata --save
import "reflect-metadata"
语法
// 在一个对象或者对象的属性上定义元数据
Reflect.defineMetadata(metadataKey, metadataValue, target);
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
// 检查对象或者属性的原型链上是否存在元数据key
let result = Reflect.hasMetadata(metadataKey, target);
let result = Reflect.hasMetadata(metadataKey, target, propertyKey);
// 检查对象或属性自身是否有元数据key
let result = Reflect.hasOwnMetadata(metadataKey, target);
let result = Reflect.hasOwnMetadata(metadataKey, target, propertyKey);
// 从对象或属性的原型链上获取元数据值
let result = Reflect.getMetadata(metadataKey, target);
let result = Reflect.getMetadata(metadataKey, target, propertyKey);
// 从对象或属性本身上获取元数据值
let result = Reflect.getOwnMetadata(metadataKey, target);
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey);
// 从对象或属性的原型链上获取所有的元数据key
let result = Reflect.getMetadataKeys(target);
let result = Reflect.getMetadataKeys(target, propertyKey);
// 从对象或属性自身获取所有的元数据key
let result = Reflect.getOwnMetadataKeys(target);
let result = Reflect.getOwnMetadataKeys(target, propertyKey);
// 从对象或属性上删除某元数据
let result = Reflect.deleteMetadata(metadataKey, target);
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey);
// 通过构造函数的装饰器设置元数据
@Reflect.metadata(metadataKey, metadataValue)
class C {
// 通过方法的装饰器设置元数据
@Reflect.metadata(metadataKey, metadataValue)
method() {
}
}
// Design-time type annotations
// 代码设计时的类型注解(译者:例如sequelize-typescript,用类型注解来定义表模型,特别方便)
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); }
// 装饰器应用
@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;
}
}
// Metadata introspection
//通过元数据实现的类型检查(译者:这里的inst应该是obj吧)
let obj = new C("a", 1);
let paramTypes = Reflect.getMetadata("design:paramtypes", inst, "add"); // [Number, Number]
reflect-metadata操作摘要 Abstract Operations
在Object上的操作
获取或创建元数据Map GetOrCreateMetadataMap ( O, P, Create )
当在对象O的属性P上获取或创建元数据Map时,会生成三个参数:对象O,属性P,boolean值表示是否创建-Create,那么会执行下面的步骤:
- 1.判断P是undefined或者IsPropertyKey(P)返回true
- 2.将targetMetadata设置为对象O的内部属性[[Metadata]] (internal slot)
- 3.如果targetMetadata是undefined的话:
- a. 如果Create是false的话,返回undefined
- b. 否则将targetMetadata设置为一个新创建的Map对象
- c. 将O的内部属性[[Metadata]]设置为targetMetadata.
- 对象的弄好了,现在来设置属性的。把metadataMap 设置为 Invoke(targetMetadata, “get”, P).
- a. 如果Create是false的话,返回undefined
- b. 否则将metadataMap设置为一个新创建的Map对象
- c. 执行 Invoke(targetMetadata, “set”, P, metadataMap).
- 返回metadataMap
这里源码中的实现,所有metadata实际上都是存放在一个var Metadata = new _WeakMap();
里边
普通的和特殊的对象行为
普通对象的内部方法和插槽
所有普通对象都有一个称为[[Metadata]]的内部槽。此内部槽的值为Null或Map对象,用于存储对象的元数据。
[[HasMetadata]] ( MetadataKey, P )
当对象O的内部函数[[HasMetadata]]被调用,传入属性P时,会执行:
- 返回 OrdinaryHasMetadata(MetadataKey, O, P).
OrdinaryHasMetadata是reflect-metadata
模块内部的一个函数
OrdinaryHasMetadata ( MetadataKey, O, P )的逻辑
执行OrdinaryHasMetadata操作时:
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 hasOwn 设置为 OrdinaryHasOwnMetadata(MetadataKey, O, P).
- 若 hasOwn 是 true, 返回 true.
- 将 parent 设置为 O.[[GetPrototypeOf]] ().
- 若 parent 不是 null, 返回 parent.[HasMetadata].
- 否则返回 false.
[[HasOwnMetadata]] ( MetadataKey, P )
HasOwnMetadata的执行步骤为:
- 返回 OrdinaryHasOwnMetadata(MetadataKey, O, P).
OrdinaryHasOwnMetadata ( MetadataKey, O, P )的逻辑
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 metadataMap 设置为 GetOrCreateMetadataMap(O, P, false).
- 若 metadataMap 是 undefined, 返回 false.
- 返回 ToBoolean(? Invoke(metadataMap, “has”, MetadataKey)).
[[GetMetadata]] ( MetadataKey, P )
返回 OrdinaryGetMetadata(MetadataKey, O, P).
OrdinaryGetMetadata ( MetadataKey, O, P )的逻辑
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 hasOwn 设置 OrdinaryHasOwnMetadata(MetadataKey, O, P).
- 若 hasOwn 是 true, 返回 OrdinaryGetOwnMetadata(MetadataKey, O, P).
- 将 parent 设置为 O.[[GetPrototypeOf]] ().
- 若 parent 不是 null, 返回 parent.[GetMetadata].
- 返回 undefined.
[[GetOwnMetadata]] ( MetadataKey, P, ParamIndex )
返回 OrdinaryGetOwnMetadata(MetadataKey, O, P).
OrdinaryGetOwnMetadata ( MetadataKey, O, P )的逻辑
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 metadataMap 设置为 GetOrCreateMetadataMap(O, P, false).
- 若 metadataMap 是 undefined, 返回 undefined.
- 返回 Invoke(metadataMap, “get”, MetadataKey).
[[DefineOwnMetadata]] ( MetadataKey, MetadataValue, P )
返回 OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P)
OrdinaryDefineOwnMetadata ( MetadataKey, MetadataValue, O, P )的逻辑
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 metadataMap 设置为 GetOrCreateMetadataMap(O, P, true).
- 返回 Invoke(metadataMap, “set”, MetadataKey, MetadataValue).
[[MetadataKeys]] ( P )
返回 OrdinaryMetadataKeys(O, P).
OrdinaryMetadataKeys ( O, P )的原理
- 判断P是undefined或者IsPropertyKey(P)返回true
- 将 ownKeys 设置为 OrdinaryOwnMetadataKeys(O, P).
- 将 parent 设置为 O.[[GetPrototypeOf]] ().
- 若 parent 是 null, 返回 ownKeys.
- 将 parentKeys 设置为 O.[[OrdinaryMetadataKeys]] ( P ).
- 将 ownKeysLen 设置为 Get(ownKeys, “length”).
- 若 ownKeysLen 是 0, 返回 parentKeys.
- 将 parentKeysLen 设置为 Get(parentKeys, “length”).
- 若 parentKeysLen 是 0, 返回 ownKeys.
- 将 set 设置为一个新创建的 Set 对象.
- 将 keys 设置为 ArrayCreate(0).
- 将 k 设置为 0.
- 遍历ownKeys中的key
- 将 hasKey 设置为 Invoke(set, “has”, key).
- 若 hasKey 是 false, 执行
- 将 Pk 设置为 ToString(k).
- 执行 Invoke(set, “add”, key).
- 将 defineStatus 设置为 CreateDataProperty(keys, Pk, key).
- 判断: defineStatus 是 true.
- k 加 1.
- 遍历parentKeys中的key
- 将 hasKey 设置为 Invoke(set, “has”, key).
- 若 hasKey 是 false, 执行
- 将 Pk 设置为 ToString(k).
- 执行 Invoke(set, “add”, key).
- 将 defineStatus 设置为 CreateDataProperty(keys, Pk, key).
- 判断: defineStatus 是 true.
- k 加 1.
- 执行 Set(keys, “length”, k).
- 返回 keys.
[[OwnMetadataKeys]] ( P )
返回OrdinaryOwnMetadataKeys(O, P).
OrdinaryOwnMetadataKeys ( O, P )原理
- Assert: P is undefined or IsPropertyKey(P) is true.
- Let keys be ? ArrayCreate(0).
- Let metadataMap be ? GetOrCreateMetadataMap(O, P, false).
- If metadataMap is undefined, return keys.
- Let keysObj be ? Invoke(metadataMap, “keys”).
- Let iterator be ? GetIterator(keysObj).
- Let k be 0.
- Let Pk be ! ToString(k).
- Let next be ? IteratorStep(iterator).
- If next is false, then
- Let setStatus be ? Set(keys, “length”, k, true).
- Assert: setStatus is true.
- Return keys.
- Let nextValue be ? IteratorValue(next).
- Let defineStatus be CreateDataPropertyOrThrow(keys, Pk, nextValue).
- If defineStatus is an abrupt completion, return ? IteratorClose(iterator, defineStatus).
- Increase k by 1.
[DeleteMetadata]">[DeleteMetadata]
- Assert: P is undefined or IsPropertyKey(P) is true.
- Let metadataMap be ? GetOrCreateMetadataMap(O, P, false).
- If metadataMap is undefined, return false.
- Return ? Invoke(metadataMap, “delete”, MetadataKey).
反射 Reflection
Reflect对象
本小节描述了对Reflect对象的修改
元数据装饰器函数
元数据装饰器函数是具有[[MetadataKey]]和[[MetadataValue]]内部槽的匿名内置函数。
当使用参数target和key调用元数据修饰器函数F时,会执行以下步骤:
- 判断F有一个叫[[MetadataKey]]的内部插槽属性,且其值是一个es语言的值,或者是undefined
- 判断F有一个叫[[MetadataValue]]的内部插槽属性,且其值是一个es语言的值,或者是undefined
- 若 Type(target) 不是 Object, 抛出 一个 TypeError 异常.
- 如果 key 不是 undefined 且 IsPropertyKey(key) 是 false, 抛出一个 TypeError 异常.
- 将 metadataKey 设置为 F的 [[MetadataKey]] 内部插槽属性的值.
- 将 metadataValue 设置为 F的 [[MetadataValue]] 内部插槽属性的值.
- 执行 target.[DefineMetadata].
- 返回 undefined.
Reflect.metadata ( metadataKey, metadataValue )函数
调用此函数时,执行下面的步骤:
- 将 decorator 设置为一个Metadata函数内新建的一个函数对象
- 将 decorator的内部插槽属性 [[MetadataKey]] 的值设置为 metadataKey.
- 将 decorator的内部插槽属性 [[MetadataKey]] 的值设置为 metadataValue.
- 返回 decorator.
Reflect.defineMetadata ( metadataKey, metadataValue, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[DefineMetadata].
Reflect.hasMetadata ( metadataKey, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[HasMetadata].
Reflect.hasOwnMetadata ( metadataKey, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[HasOwn].
Reflect.getMetadata ( metadataKey, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[GetMetadata].
Reflect.getOwnMetadata ( metadataKey, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[GetOwnMetadata].
Reflect.getMetadataKeys ( target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[[GetMetadataKeys]] (propertyKey).
Reflect.getOwnMetadataKeys ( target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[[GetOwnMetadataKeys]] (propertyKey).
Reflect.deleteMetadata ( metadataKey, target [, propertyKey] )函数
- 若 Type(target) 不是 Object, 抛出 TypeError 异常.
- 返回 target.[DeleteMetadata].
本文链接:https://www.zoucz.com/blog/2020/07/29/cd995ad0-d1a5-11ea-90b5-eb40e9720ed0/