3

ECMAScript Reflect Metadata 提案

 2 years ago
source link: https://www.zoucz.com/blog/2020/07/29/cd995ad0-d1a5-11ea-90b5-eb40e9720ed0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ECMAScript Reflect Metadata 提案

作者: 邹成卓 2020-07-29 22:14:23 分类: javascript

标签: javascript

评论数:

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

在不少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.
  • 遍历parentKeys中的key
    • 将 hasKey 设置为 Invoke(set, “has”, key).
    • 若 hasKey 是 false, 执行
      • 将 Pk 设置为 ToString(k).
      • 执行 Invoke(set, “add”, key).
      • 将 defineStatus 设置为 CreateDataProperty(keys, Pk, key).
      • 判断: defineStatus 是 true.
  • 执行 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/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK