前端发展很快,新鲜的工具、框架,甚至语言层出不穷。这虽然提高了开发效率和项目质量,但是从某种程度上来说也让学习曲线变的陡峭了一点。

在不少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].

☞ 参与评论