decorate方法
declare type ClassDecorator = <TFunction exntends Function>(target: TFunction) ⇒ TFunction | void;
function decorate(decorators: ClassDecorator[], target: Function): Function;
-
对类的装饰
对类的装饰该方法有几个参数, 分别是:
- @param {Array} decorators - 装饰器的数组
- @param {Object} target - 目标对象
- @returns 返回应用提供的装饰器后的值
- 注意: 装饰器应用是与array的位置方向相反, 为从右往左.
来个?:给TestCkassDecorator类添加或者修改sayName方法
const classDecorator: ClassDecorator = target => { target.prototype.sayName = () => console.log('veloma'); // return target; 这里可以return也可以不return, 因为target是一个对象引用 } class TestClassDecorator { constructor(public name = '') {} sayName() { console.log(this.name); } } Reflect.decorate([classDecorator], TestClassDecorator); // 对类进行修饰 const t = new TestClassDecorator('nihao'); t.sayName(); // veloma
注意:在classDecorator中传入的target, 只能修改其prototype的方法, 不能修改其属性, 因为其属性是
ready-only
-
对属性或方法的装饰
对属性或方法的修饰有几个参数, 分别是:
- @param {Array} decorators - 装饰器的集合
- @param {Object} target - 目标对象
- @param {string} key - 要装饰的属性名称
- @param {Object} descriptor - 该属性的描述
注意: descriptor分为两种, 一种是数据描述符, 一种是存取描述符
// 数据描述符 { value: 'aaa', configurable: true, writable: true, enumerable: true } // 存取描述符 { get() {return 1}, set() { console.log('set') }, configurable: true, enumerable: true }
属性装饰器: AOP编程, 在原方法的后面加上操作
const propertyDecorator: PropertyDecorator = (target, propertyKey) => { const origin = target[propertyKey]; target[propertyKey] = () => { origin.call(target); console.log('added override'); } } class PropertyAndMethodExample { static staticProperty() { console.log('im static property'); } method() { console.log('im one instance method'); } } // 装饰PropertyAndMethodExample的staticProperty方法(静态方法) Reflect.decorate([propertyDecorator], PropertyAndMethodExample, 'staticProperty'); PropertyAndMethodExample.staticProperty(); // im static property \n added override
方法装饰器
const methodDecorator: MethodDecorator = (target, propertyKey, descriptor) => { // 将其描述改为不可编辑 descriptor.configurable = false; descriptor.writable = false; return descriptor; } class PropertyAndMethodExample { static staticProperty() { console.log('im static property'); } method() { console.log('im one instance method'); } } // 获取原descriptor let descriptor = Object.getOwnPropertyDescriptor(PropertyAndMethodExample.prototype, 'method'); // 获取修改后的descriptor descriptor = Reflect.decorate([methodDecorator], PropertyAndMethodExample, 'method', descriptor); // 将修改后的descriptor添加到对应的方法上 Reflect.defineProperty(PropertyAndMethodExample.prototype, 'method', descriptor); const example = new PropertyAndMethodExample(); example.method = () => console.log('override'); // 报错: 因为已经将该方法(属性)的writable描述符设置为false
metadata方法
/**
* @param {string} metadataKey - 元数据入口的key
* @param {*} metadataValue 元数据入口的value
* @returns 装饰器函数
*/
function metadata(metadataKey: any, metadataValue: any) {
(target: Function): void;
(target: Object, propertyKey: string | symbol): void;
}
实例
const nameSymbol = Symbol('veloma');
// 类元数据
@Reflect.metadata('class', 'class');
class MetaDataClass {
// 实例属性元数据
@Reflect.metadata(nameSymbol, 'nihao')
public name = 'origin';
// 实例方法元数据
@Reflect.metadata('getName', 'getName')
public getName() {}
// 静态方法元数据
@Reflect.metadata('static', 'static')
static staticMethod() {}
}
// 创建元数据类的实例
const metadataInstance = new MetaDataClass();
// 获取MetaDataClass的name元数据
const value = Reflect.getMetadata('name', MetaDataClass); // undefined
// 获取实例中name属性的nameSymbol元数据
const name = Reflect.getMetadata(nameSymbol, metadataInstance, 'name'); // nihao
// 获取实例中getName属性的getName元数据
const methodVal = Reflect.getMetadata('getName', metadataInstance, 'getName'); // getName
// 获取元数据类的staticMethod属性的static元数据
const staticVal = Reflect.getMetadata('static', MetaDataClass, 'staticMethod'); // static
console.log(value, name, methodVal, staticVal); // undefined nihao getName static
defineMetadata方法
该方法是metadata
的定义版本, 也就是非@版本, 会多穿一个参数target
, 表示待装饰的对象
/**
* @param {string} metadataKey - 设置或获取时的key
* @param {*} metadataValue - 元数据内容
* @param {Object} target - 待装饰的target
* @param {string} targetKey - target的property
*/
function defineMetadata(metadataKey: any, metadataValue: any, target: Object, targetKey: string | symbol): void;
示例
class DefineMetadata {
static staticMethod() {}
static staticProperty = 'static';
getName() {}
}
const type = 'type';
// 给DefineMetadata设置元数据type, 值为class
Reflect.defineMetadata(type, 'class', DefineMetadata);
// 给DefineMetadata.staticMethod设置元数据type, 值为staticMethod
Reflect.defineMetadata(type, 'staticMethod', DefineMetadata.staticMethod);
// 给DefineMeatadata.prorotype.getName设置元数据type, 值为method
Reflect.defineMetadata(type, 'method', DefineMetadata.prorotype.getName);
// 给DefineMetadata的staticProperty属性设置元数据type, 值为staticProperty
Reflect.defineMetadata(type, 'staticProperty', DefineMetadata, 'staticProperty');
// 获取DefineMetadata身上的type元数据
const t1 = Reflect.getMetadata(type, DefineMetadata); // class
// 获取DefineMetadata.staticMethod身上的type元数据
const t2 = Reflect.getMetadata(type, DefineMetadata.staticMethod); // staticMethod
// 获取DefineMetadata.prototype.getName身上的type元数据
const t3 = Reflect.getMetadata(type, DefineMetadata.prototype.getName); // method
// 获取DefineMetadata上staticProperty属性的type元数据
const t4 = Reflect.getMetadata(type, DefineMetadata, 'staticProperty'); // staticProperty
console.log(t1, t2, t3, t4); // class staticMethod method staticProperty
注意: t4定义和获取不一样的地方, 比如t2到t3都有两种写法, 一种就是将target转换为对应的对象且必须是对象, 以t2为例, 也可以写为
Reflect.defineMetadata(type, 'staticMethods', DefineMetadata, 'staticMethod');
const t2 = Reflect.getMetadata(type, DefineMetadata, 'staticMethod');
注意: 这两种方式不能混合使用, 比如下面这种是不对的:
Reflect.defineMetadata(type, 'staticMethod', DefineMetadata, 'staticMethod');
const t2 = Reflect.getMetadata(type, DefineMetadata.staticMethod);
hasMetadata方法
该方法返回布尔值, 表明该target或其原型链上有没有对应的元数据
/**
* @param {string} metadataKey - 元数据的key
* @param {Obejct} target - 定义的对象
* @param {string} targetKey - 定义对象的属性(重载参数), 可选
* @returns 在target或其原型链上返回true.
*/
function hasMetadata(metadataKey: string, target: Object, targetKey?: symbol | string): boolean;
示例
const type = 'type';
class HasMetadataClass {
@Reflect.metadata(type, 'staticProperty')
static staticProperty = '';
}
// 给HasMetadataClass定义一个type元数据, 值为class
Reflect.defineMetadata(type, 'class', HasMetadataClass);
const t1 = Reflect.hasMetadata(type, HasMetadataClass); // true
const t2 = Reflect.hasMetadata(type, HasMetadataClass, 'staticProperty'); // true
console.log(t1, t2); // true true
其余的像实例属性/方法, 静态方法都以此类推
hasOwnMetadata方法
跟Object.prototype.hasOwnProperty
类似, 是只查找对象上的元数据, 而不会继续想上查找原型链上的, 其余的跟hasMetadata一致
const type = 'type';
class Parent {
@Reflect.metadata(type, 'getName')
getName() {}
}
@Reflect.metadata(type, 'class')
class HasOwnMetadataClass extends Parent {
@Reflect.metadata(type, 'static')
static staticProperty() {}
@Reflect.metadata(type, 'method')
method() {}
}
// 判断HasOwnMetadataClass有没有type这个元数据
const t1 = Reflect.hasOwnProperty(type, HasOwnMetadataClass); // true
// 判断HasOwnMetadataClass的staticProperty属性有没有type这个元数据
const t2 = Reflect.hasOwnMetadata(type, HasOwnMetadataClass, 'staticProperty'); // true
// 判断HasOwnMetadataClass.prototype的method属性有没有type这个元数据
const t3 = Reflect.hasOwnMetadata(type, HasOwnMetadataClass.prototype, 'method'); // true
// 判断HasOwnMetadataClass.prototype的getName属性有没有type这个元数据
const t4 = Reflect.hasOwnMetadata(type, HasOwnMetadataClass.prototype, 'getName'); // false
// 判断HasOwnMetadataClass.prototype的getName属性有没有type这个元数据, 这里的结果为true, 因为HasOwnMetadata.prototype上面没有这个属性, 但是HasOwnMetadata的原型链上有getName这个属性
const t5 = Reflect.hasMetadata(type, HasOwnMetadataClass.prototype, 'getName'); // true
console.log(t1, t2, t3, t4, t5); // true true true false true
注意: t4和t5的区别
getMetadata方法
这个属性在之前验证各个属性的时候就已经使用过了, 就是用于获取target的元数据值, 会往原型链上找
/**
* @param {string} metadataKey - 元数据key
* @param {Object} target - 元数据定义的target
* @param {string} targetKey - 可选项, 是否选择target的某个key
* @returns 如果找到了元数据则返回元数据值, 否则返回undefined
**/
function getMetadata(metadataKey: string, target: Object, targetKey?: string | symbol): any;
getOwnMetadata方法
与hasOwnMetadata和hasMetadata的区别一样, 是否往原型链上找
getMetadataKeys方法
类似Object.keys
, 返回该target以及原型链上target的所有元数据的keys
const type = 'type';
@Reflect.metadata('parent', 'parent')
class Parent {
getName() {}
}
@Reflect.metadata(type, 'class')
class HasOwnMetadataClass extends Parent {
@Reflect.metadata(type, 'static')
static staticProperty() {}
@Reflect.metadata('bbb', 'method')
@Reflect.metadata('aaa', 'method')
method() {}
}
// 获取HasOwnMetadataClass身上以及原型链上的所有元数据
const t1 = Reflect.getMetadataKeys(HasOwnMetadataClass); // type parent
// 获取HasOwnMetadataClass中method属性身上的以及原型链上的所有元数据
const t2 = Reflect.getMetadataKeys(HasOwnMetadataClass.prototype, 'method'); // aaa bbb
t1很好理解, 因为会向上找原型链的parent, t2好像多了一些东西, desingn: 开头的, 先不管他, 看看aaa 和 bbb 的顺序是和我们添加的顺序是相反的, 还记得之前说过装饰器的顺序是从右到左的, 所以先应用bbb aaa在应用design:
getOwnMetadataKeys方法
跟getMetadataKeys一样, 只是不向原型链中查找
deleteMetadata方法
用于删除元数据
/**
* @param {string} metadataKey - 元数据key
* @param {Object} target - 元数据定义的对象
* @param {string} targetKey - 对象对应的key, 可选参数
* @returns 如果对象上有该元数据, 返回true, 否则返回false
*/
function deleteMetadata(metadataKey: string, target: Object, targetKey?: symbol | string): boolean;
示例
const type = 'type';
@Reflect.metadata(type, 'class')
class DeleteMetadata {
@Reflect.metadata(type, 'static')
static staticMethod() {}
}
// 删除DeleteMetadata身上的type元数据
const res1 = Reflect.deleteMetadata(type, DeleteMetadata); // true
// 删除DeleteMetadata上staticMethod属性身上的type元数据
const res2 = Reflect.deleteMetadata(type, DelteMetadata, 'staticMethod'); // true
// 再次删除DelelteMetadata身上的type元数据, 这次返回false, 因为在之前已经删除过了
const res3 = Reflect.deleteMetadata(type, DelteMetadata); // false
console.log(res1, res2, res3); // true true false
design:
好了还有一个问题没有解决, 就是之前说的在getMetadataKey时出现的design:xxx
的内容是怎么来的, 表示什么意思呢?design:type
表示被装饰的对象是什么类型, 比如是字符串? 数字? 还是函数等. design:paramtypes
表示被装饰对象的参数类型, 是一个表示类型的数组, 如果不是函数, 则没有该key.design:returntype
表示被装饰对象的返回值属性, 比如字符串, 数字或函数等.
示例
@Reflect.metadata('type', 'class')
class A {
constructor(public name: string, public age: number) {}
@Reflect.metadata(undefined, undefined)
method(): boolean {
return true;
}
}
// 获取A的design:paramtypes元数据
const t1 = Reflect.getMetadata('design:paramtypes', A); // [[Function: String], [Function: Number]]
// 获取A.prototype上的method属性的design:returntype元数据
const t2 = Reflect.getMetadata('design:returntype', A.prototype, 'method'); // [Function: Boolean]
// 获取A.prototype上的method属性的design:type元数据
const t3 = Reflect.getMetadata('design:type', A.prototype, 'method'); // [Function: Function]
console.log(t1, t2, t3); // [[Function: String], [Function: Number], [Function: Boolean], [Function: Function]]
注意:
- 没有装饰的target是get不到这些metadata的
- 必须手动指定类型, 无法进行推断, 比如method方法如果不指定, 返回值为
boolean
, 那么t2将是undefined
- 应用的顺序为:
type → paramtypes → returntype
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!