装饰器
-
装饰器:是一种特殊类型的声明,他能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗来讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
装饰器就是过去几年中js最大的成熟之一,已是Es7的标准特性之一 -
类装饰器:
类装饰器在声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数//普通装饰器(无法传参) //装饰器 function logClass(params:any){ //params就是当前类 console.log(params); //f HttpClient() {} params.prototype.apiUrl = "xxxx"//相当于动态扩展的属性 params.prototype.run = function(){ console.log("run") } } @logClass class HttpClient{ constructor(){} getData(){} } var http:any = new HttpClient(); console.log(http.apiUrl);//xxxx http.run();//run
//装饰器工厂(可传参) //装饰器 function logClass(params:string){ return function(target:any){ console.log(target); //f HttpClient() {} console.log(params); //http://www.abc.com target.prototype.apiUrl = params;//相当于动态扩展的属性 } } @logClass("http://www.abc.com") class HttpClient{ constructor(){} getData(){} } var http:any = new HttpClient(); console.log(http.apiUrl);//http://www.abc.com
重载构造函数的例子:
类装饰器表达式会在运行时当做函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,他会使用提供的构造函数来替换类的声明。function logClass(target:any){ console.log(target);// f HttpClient(){this.apiUrl="构造函数里的apiUrl"} return class extends target { apiUrl:any = "修改的apiUrl"; getData(){ this.apiUrl = this.apiUrl+"----"; console.log(this.apiUrl); } } } @logClass() class HttpClient{ public apiUrl:string|undefined; constructor(){ this.apiUrl="构造函数里的apiUrl" } getData(){ console.log(this.apiUrl) } } var http = new HttpClient(); http.getData();//修改的apiUrl----
-
属性装饰器
属性装饰器表达式会在运行时当做函数被调用,传入下2个各参数;- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
//类装饰器 function logClass(params:string){ return function(target:any){ console.log(target); //f HttpClient() {} console.log(params); //http://www.abc.com target.prototype.apiUrl = params;//相当于动态扩展的属性 } } //属性装饰器 function logProperty(params:any){ return function(target:any,attr:any){ console.log(targrt);//{getData:f,constructor:f} console.log(attr);//url target[attr] = params; } } @logClass("xxxx") class HttpClient{ @logProperty("http://www.abc.com") //属性装饰器后面不能加分号 public url:any|undefined; constructor(){} getData(){ console.log(this.url) } } var http:any = new HttpClient(); http.getData();//http://www.abc.com
-
方法装饰器
它会被用应到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:- 于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
- 成员的属性描述符
//方法装饰器一 function get(params:any){ return function(target:any,methodName:any,desc:any){ console.log(target)//{getData:f,constructor}原型对象 console.log(methodName)//getData当前方法的名称 console.log(desc)//{value:f,writable:true,enumerable:true,configurable:true}描述当前的方法,value就是当前的方法 target.apiUrl="xxxx"; target.run = function(){ console.log("run") } } } class HttpClient{ public url:any|undefined; constructor(){} @get("http://www.abc.com") getData(){ console.log(this.url) } } var http = new HttpClient(); console.log(http.apiUrl)//xxxx http.run()//run
//方法装饰器二 function get(params:any){ return function(target:any,methodName:any,desc:any){ console.log(target)//{getData:f,constructor}原型对象 console.log(methodName)//getData当前方法的名称 console.log(desc)//{value:f,writable:true,enumerable:true,configurable:true}描述当前的方法,value就是当前的方法 //修改装饰器的方法 把装饰器方法里面传入的所有参数改为string类型 //1、保存当前的方法 var oMethod = desc.value; desc.value = function(...args:any[]){ args=args.map((val)=>{ return String(val) }) console.log(args);//["aaa","xxx"] oMethod.apply(this.args); } } } class HttpClient{ public url:any|undefined; constructor(){} @get("http://www.abc.com") getData(...args:any){ console.log(args);//["aaa","xxx"] console.log("getData里的方法")//getData里的方法 } } var http = new HttpClient(); http .getData(aaa,"xxx")
-
方法参数装饰器
参数装饰器表达式会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 参数的名字
- 参数在函数参数列表中的索引
function logParams(params:any){ return function(target:any,paramsName:any,paramsIndex:any){ console.log(params);//xxxx console.log(targrt);//{getData:f,constructor:f} console.log(paramsName);//getData console.log(paramsIndex);//0 target.apiUrl=params; } } class HttpClient{ public url:any|undefined; constructor(){} getData(@logParams("xxxx") uuid:any){ console.log(uuid)//123123 } } var http:any = new HttpClient(); http .getData(123123); console.log(http.apiUrl);//xxxx
-
装饰器执行顺序:
属性>方法>方法参数>类
如果有多个同样的装饰器,先执行后面的function logClass1(params:any){ return function(target:any){ console.log("装饰器1"); } } function logClass2(params:any){ return function(target:any){ console.log("装饰器2"); } } function logAttribute(params?:string){ return function(target:any,attrName:any){ console.log("属性装饰器"); } } function logMethod(params?:string){ return function(target:any,attrName:any,desc:any){ console.log("方法装饰器"); } } function logParams1(params?:string){ return function(target:any,attrName:any,desc:any){ console.log("方法参数装饰器1"); } } function logParams2(params?:string){ return function(target:any,attrName:any,desc:any){ console.log("方法参数装饰器1=2"); } } @logClass2("aaa") @logClass2("xxx") class HttpClient{ @logAttribute() public apiUrl:any|undefined; constructor(){} @logMethod() getData(){ return true; } setData(@logParams1() attr1:any,@logParams2 attr2:any){ } } var http:any = new HttpClient(); //属性装饰器 //方法装饰器 //方法参数装饰器2 //方法参数装饰器1 //类装饰器2 //类装饰器1