装饰器
装饰器是一种特殊类型的声明,它能够被附件到类声明,方法,属性或参数上,可以修改其行为扩展其功能。
分类:类装饰器、属性装饰器、方法装饰器、参数装饰器
写法包含:普通装饰器(无法传参)、装饰器工厂(可传参)
要启用对decorator的实验支持,您必须在命令行或tsconfig.json中启用experimental aldecorators编译器选项
tsc --target ES5 --experimentalDecorators
---------------------------tsconfig.ts--------------
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
类装饰器
类装饰器在类声明之前被声明(紧靠着类声明),类装饰器应用于类构造函数,可以用来监视、修改或替换类定义。在不修改类前提下可以扩展类属性
//普通类装饰器 执行顺序order1->order2
function logClass(params:any){
console.log("order1")
console.log(params);// params 为class Httpclient
params.prototype.name='12动态扩展属性'// 使用es5的方式扩展属性和方法
}
@logClass
class Httpclient{
constructor(){
console.log("order2")
}
getDate(){
}
}
let h:any = new Httpclient();
console.log(h.name);
//===================================
执行顺序为order1->order2->order3
// 装饰器修改类构造函数,类装饰器重载构造函数
function logClass(target:any){// 此处为装饰器传入的参数
console.log("order1")
return class extends target{// 重载方法及其属性,'class extends',此处重写了class Httpclient
apiurl:string
constructor(){
super()
console.log("order3")
this.apiurl = '123';
}
getDate(){ }
}
}
@logClass
class Httpclient{
apiurl!:string;
constructor(){
console.log("order2")
this.apiurl='2.apiurl'
}
getDate(){ }
}
let h = new Httpclient();
console.log(h.apiurl)
//===================================
// 装饰器工厂 执行顺序order1->order2->order3
function logClass(param:string){// 此处为装饰器传入的参数
console.log("order1")
return function(target:any){ // 工厂装饰器返回为一个函数,函数参数为class Httpclient
target.prototype.apiurl = '1.apiurl'
console.log("order2")
}
}
@logClass("param1")
class Httpclient{
apiurl!:string;
constructor(){
// this.apiurl='2.apiurl'
console.log("order3")
}
getDate(){
}
}
let h = new Httpclient();
console.log(h.apiurl)
//======
// 类装饰器
function logClass(param:any){// 此处为装饰器传入的参数
console.log("order1")
// return class extends param{ // 写法对应为 @logClass
// apiurl!:string;
// getDate(){}
// }
// return function(target:any){ // 写法对应为@logClass('param') ,工厂装饰器返回为一个函数,函数参数为class Httpclient ,
// target.prototype.apiurl = '1.apiurl'
// console.log("order2")
// }
}
属性装饰器
属性装饰器的执行顺序早于在类装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字
// 属性装饰器
function logProperties(param?:any,param2?:string){// 该函数参数个数及类型根据功能需求而定
console.log("order4|")
return function(target:any,attr:any){
console.log("order5+")
target[attr]=''
}
}
class Httpclient{
@logProperties('dd') // 当作函数被调用
apiurl:string;
constructor(){
this.apiurl='2.apiurl'
console.log("order3")
}
getDate(){
}
}
let h = new Httpclient();
方法装饰器
它被应用到方法的属性描述上,可以用来监视,修改或者替换方法定义。
方法装饰器会在运行时传入下列三个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 方法的名称
- 方法的属性描述
// 方法装饰器
function get(param:any){
return function(target:any,methodName:any,desc:any){
/*三个参数为
1-----
Httpclient { getDate: [Function], apiurl: '' },
getDate,
{ value: [Function],
writable: true,
enumerable: true,
configurable: true }
2-----
*/
target.apiurlww2 = '1.apiurlww2'// 扩展原型类属性 不使用es5 prototype方式
target.run= function(param1:string):any{// 扩展原型类方法
return "run+"+param1;
}
desc.value= function(age:number):any{// 替换重写装饰器方法
return 'getDate Method decorated'+age;
}
// 修改装饰器
var oriMethod = desc.value;
desc.value= function():any{// 修改装饰器方法
var mes= 'getDate Method decorated';
console.log(mes);
oriMethod.apply(this,console.log(mes)) // apply方法使用作为修改装饰器
return mes
}
}
}
class Httpclient{
@get('ww')
getDate(){
}
}
console.log(h.apiurlww2)
console.log(h.run('ww'))
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
// 方法装饰器
function get(target:any,methodName:any,desc:any){
var oriMethod = desc.value;
desc.value= function():any{// 替换装饰器方法
var mes= 'getDate Method decorated';
console.log(mes);
oriMethod.apply(this,console.log(mes))
// return mes
}
}
使用为@get
class Httpclient{
@get
getDate(){
}
}
方法参数装饰器
参数装饰器表达式会在运行时单过函数被调用,可以使用参数装饰器为类的原型增加一些元数据,传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 参数的名称
- 参数在函数参数列表中的索引
import "reflect-metadata";
const requiredMetadataKey = Symbol("required");
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(@required name: string) {
return "Hello " + name + ", " + this.greeting;
}
}
装饰器执行顺序
属性装饰器【多个则从下到上执行】 -> 方法装饰器【多个则从下到上执行】 -> 方法参数装饰器【多个则从右到左执行】 -> 类装饰器【多个则从下到上执行】
参数装饰器
方法装饰器
@required @validate