(Decorators)是一种特殊类型的声明,它可以被附加到类声明,方法,属性或参数上。
装饰器由@符号紧接一个函数名称,如@expression,expression求值后必须是一个函数,
在函数执行的时候装饰器的声明方法会被执行。
装饰器是用来给附着的主体进行装饰,添加额外行为的。
感觉typescript的装饰器就是Java的注解,'C#'的特性,算是一种元编程,
定义在对象上,用于代码执行前后,做额外的事情,主要提供面向截面编程。
TypeScript官方介绍:
装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。
Javascript里的装饰器目前处在建议征集的第一阶段,但在TypeScript里已做为一项实验性特性予以支持。
注意:装饰器是一项实验性特性,在未来的版本中可能会发生改变。
若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器
选项:
命令行: tsc --target ES5 --experimentalDecorators
tsconfig.json文件启用:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
装饰器求值:
类中不同声明的装饰器将按以下规定的顺序应用:
1.参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个实例成员。
2.参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰其应用到每个静态成员。
3.参数装饰器应用到构造函数。
4.类装饰器应用到类。
类装饰器:
1.在类声明之前声明,类装饰器应用于类的构造函数,可以用来监视,修改或替换类定义。
重点1:类装饰器表达式会在运行时当做函数被调用,类的构造函数被当做其唯一的参数。
重点2:如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
(也就是说,可以用类装饰器返回一个函数的形式来动态替换类的原本构造函数)。
注意: 如:
@sealed
class Greeter{
greeter:string;
constructor(message:string){
this.greeter=message;
}
greeter(){
return "hello"+this.greeter;
}
}
//@sealed装饰器定义如下
function sealed(constructor:Function){
Object.seal(constructor);
Object.seal(constructor.protected);
//当@sealed被执行时它将密封该了类的构造函数和原型。
}
方法装饰器:
声明在一个方法的声明之前,它会被用到方法的属性描述符上(descriptor),
可以用来监视,修改或替换方法定义。
方法装饰器不能用在声明文件(.d.ts), 重载或者任何外部上下(比如declare的类中)中。
方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
1.target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2.propertyKey:方法(成员)的名称。
3.descriptor:成员的属性描述符。
注意:
如果代码的输出版本小于ES5,属性描述符将会是undefined。
如果方法装饰器的返回一个值,它会被用作方法的属性描述符,如果代码的输出目标小于ES5,
返回值会被忽略。
其中descriptor类型为TypedPropertyDescriptor, 在typescript中定义如下:
interface TYpedPropertyDescriptor {
enumerable?:boolean; //是否可遍历
configurable?:boolean; //属性描述是否可改变或者属性是否可删除
writable?:boolean; //是否可修改
value?:T; //属性的值
get?:()=>T; //属性的访问器函数(getter)
set?:(value:T)=>void //属性的设置器函数
}
如:
class TestClass{
@log
testMethod(arg:string){
return "xzm:"+arg;
}
}
//装饰器@log的实现:
function log(
target:Object,
properrtyKey:string,
descriptor:TypedPropertyDescriptor
){
let origin=descriptor.value; //通过方法属性描述符的value属性,取得有关方法对象
descriptor.value=function(...args:any[]){
console.log("args:"+JSON.stringify(args)); //调用前
let result=origin.apply(this,args); //调用方法
console.log("The result" + result);
return result;
}
return descriptor;
}
//使用代码测试:
new TestClass().testMethod("test method descorator");
//结果输出如下:
//agrs:["test method descorator"]
//The result-xzm:test method descorator
访问器装饰器:
访问器装饰器声明在一个访问器声明之前。
访问器装饰器应用于访问器的属性描述符(),并且可以用来监视,修改或替换一个访问器定义。
注意:
TypeScript不允许同时装饰一个成员的set或者get访问器。
取而代之的是,一个成员的所有装饰必须应用在文档顺序的第一个访问器上。
这是因为, 在装饰器应用于一个属性描述符时,它联合了get和set访问器,而不是分开声明的。
访问器装饰器表达式会在运行时当做函数被调用,传入下列3个参数:
1.target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2.properrtyKey:方法(成员)的名称。
3.descriptor:成员的属性描述符。 访问器装饰器基本和方法装饰器一样,
除了需要注意上面提到的不允许同时装饰一个成员的set和get访问器以外。
属性装饰器:
属性装饰器声明在一个属性声明之前,属性装饰器表达式会在运行时当做函数被调用,传入下列两个参数:
1.target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2.property:成员(属性)的名字。
注意:属性描述符不会作为参数传入属性装饰器,这于TypeScript是如何初始化属性装饰器有关。
因为目前没有办法在顶一个原型对象的成员时描述一个实例的属性, 并且没办法监视或修改一个属性的
初始化方法。因此属性描述符只能用来监视类中是否声明了某个名字的属性。
参数装饰器:
声明在一个参数声明之前(用于的类的构造函数或方法声明),参数装饰器表达式会在运行是被当做函数调用
1.target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2.propertyKey:成员的名字。
3.parameterIndex:参数在函数参数列表中的索引。 注意:参数装饰器只能用来监视一个方法的参数
是否被传入。
参数装饰器在Angular中被广泛使用,特别是结合reflect-metadata库来支持实验性的Metadata
API。
参数装饰器的返回值会被忽略。
装饰器组合:
TypeScript支持多个装饰器同时应用到一个声明上,实现多个装饰器复合使用,语法支持从左到右,
或从上到下书写。
在TypeScript里,当多个装饰器应用在一个声明上的时候,会进行如下步骤的操作:
1.从左到右(从上到下)依次执行装饰器函数,得到返回结果。
2.返回的结果会被当做函数,从左到右(从上倒下)依次调用。
摘自 https://www.aliyun.com/jiaocheng/812629.html
网友评论