我最后摆弄了一下装饰器,并决定在任何文档发布之前为任何想要利用这一点的人记录我发现的东西。如果你发现任何错误,请随意编辑。
一般分
在声明类时调用装饰器,而不是在实例化对象时调用装饰器。
可以在同一个类/属性/方法/参数上定义多个装饰器。
构造函数上不允许使用装饰符。
一个有效的装饰符应该是:
可赋值给其中一个Decorator类型(ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator)。
返回一个值(在类装饰器和方法装饰器的情况下),该值可分配给被装饰的值。
参考
方法/形式访问器装饰器
实现参数:
target:类的原型(Object)。
propertyKey:方法的名称(字符串|符号)。
描述符:TypedPropertyDescriptor——如果你不熟悉描述符的键,我建议你在Object.defineProperty的文档中阅读它(它是第三个参数)。
示例-无参数
Use:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
实现:
function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
const originalMethod = descriptor.value; // save a reference to the original method
// NOTE: Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method (see notes below)
descriptor.value = function(...args: any[]) {
// pre
console.log("The method args are: " + JSON.stringify(args));
// run and store result
const result = originalMethod.apply(this, args);
// post
console.log("The return value is: " + result);
// return the result of the original method (or modify it before returning)
return result;
};
return descriptor;
}
输入:
new MyClass().myMethod("testing");
输出:
方法参数是:["testing"]
返回值为:Message——testing
注:
Do not use arrow syntax when setting the descriptor's value. The context of this will not be the instance's if you do.
It's better to modify the original descriptor than overwriting the current one by returning a new descriptor. This allows you to use multiple decorators that edit the descriptor without overwriting what another decorator did. Doing this allows you to use something like @enumerable(false) and @log at the same time (Example: Bad vs Good)
Useful: The type argument of TypedPropertyDescriptor can be used to restrict what method signatures (Method Example) or accessor signatures (Accessor Example) the decorator can be put on.
示例-带参数(Decorator Factory)
使用实参时,必须声明带有装饰器形参的函数,然后返回带有示例签名的不带实参的函数。
class MyClass {
@enumerable(false)
get prop() {
return true;
}
}
function enumerable(isEnumerable: boolean) {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
descriptor.enumerable = isEnumerable;
return descriptor;
};
}
静态方法装饰器
类似于方法装饰器,但有一些不同:
它的目标参数是构造函数本身,而不是原型。
描述符是在构造函数而不是原型上定义的。
类的修饰符
@isTestable
class MyClass {}
实现参数:
target:声明装饰器的类(TFunction扩展Function)。
示例:使用元数据api存储类的信息。
房地产装饰
class MyClass {
@serialize
name: string;
}
实现参数:
target:类的原型(Object)。
propertyKey:属性名称(字符串|符号)。
示例:创建@serialize("serializedName")装饰器,并将属性名添加到要序列化的属性列表中。
参数装饰
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
实现参数:
目标:类的原型(函数-函数似乎不再工作了。您现在应该在这里使用any或Object,以便在任何类中使用装饰器。或者指定你想要限制它的类类型)
propertyKey:方法的名称(字符串|符号)。
parameterIndex: parameter在函数参数列表中的索引(number)。
简单的例子
详细的例子(年代)
Memoize decorator -方法,获取/设置访问器装饰器示例