什么是装饰器?
装饰器:装饰器是一种特殊类型的声明,它能够附加到类声明、方法、属性和参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器:类装饰器,属性装饰器,方法装饰器,参数装饰器。
装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)
装饰器是过去几年中js最伟大的成就之一,已是ES7的标准特性之一
1.类装饰器:类装饰器在紧靠类声明前声明。类装饰器应用于类构造函数,可以用来监视、修改或替换类定义,传入一个参数
修改tsconfig.json,"experimentalDecorators": true,
1.1类装饰器(普通装饰器)
// 普通装饰器(无法传参数) function logClass(params:any){ console.log(params) // "ƒ HttpClient() {}",params就是当前类,可以扩展类的属性和方法 params.prototype.apiUrl='htttp://xxx' // 扩展类 params.prototype.run=function(){ // 扩展方法 console.log('run方法') } } @logClass // 紧靠类声明装饰器,后面不加分号 class HttpClient{ constructor(){ } getData(){ } } let http:any = new HttpClient(); console.log(http.apiUrl); // "htttp://xxx" http.run() // "run方法"
1.2类装饰器(装饰器工厂)
// 装饰器工厂(可传参) function logClass(params:string){ return function(target:any){ console.log(params) // "hello",获取到传入的参数 console.log(target) // "ƒ HttpClient() {}" target.prototype.uriApi="http://xxx" // 扩展属性 target.prototype.run=function(){ // 扩展方法 console.log('扩展方法run') } } } @logClass('hello') // 紧靠类声明装饰器,后面不加分号 class HttpClient{ constructor(){ } getData(){ } } let http:any = new HttpClient(); console.log(http.uriApi) // "http://xxx" http.run() // '扩展方法run'
// 重载构造函数 function logClass(target:any){ return class extends target{ // target就是当前类 urlApi:any="/api" // 替换类里的属性和方法 getData(){ this.urlApi=this.urlApi+"/index" console.log(this.urlApi) } } } @logClass class HttpClient{ public urlApi:string |undefined constructor(){ this.urlApi=="/admin" } getData(){ console.log(this.urlApi) } } let http:any = new HttpClient(); console.log(http.urlApi) // "/api" http.getData() // "/api/index"
2.属性装饰器:接收两个参数
第一个参数:对静态成员来说是类的构造函数,对实例成员来说是类的原型对象
第二个参数:成员的名字
// 属性装饰器 function logProprety(params:any){ return function(target:any,attr:any){ console.log(target) // {getData: ƒ, constructor: ƒ},类的原型对象,这里的target相当于上面类装饰器的target.prototype console.log(attr) // urlApi,属性名 target[attr] = params } } class HttpClient{ @logProprety('/api') public urlApi:string |undefined constructor(){ } getData(){ console.log(this.urlApi) } } let http:any = new HttpClient(); console.log(http.urlApi) // /api http.getData() // /api
3.方法装饰器:用于方法的属性描述符上,可以监视、修改、替换方法定义;接收三个参数
第一个参数:类的原型对象
第二个参数:成员的名字
第三个参数:成员的属性描述符
// 方法装饰器 function logMethod(params:any){ return function(target:any,methodName:any,desc:any){ console.log(params) // 456,传入的参数 console.log(target) // {getData: ƒ, constructor: ƒ},原型对象 console.log(methodName) // getData,方法名 console.log(desc) // {writable: true, enumerable: true, configurable: true, value: ƒ} ,方法描述 console.log(desc.value) // ƒ () {console.log(this.urlApi);} target.api='xxx' // 扩展属性和方法 target.run=function(){ console.log('run方法') } target.getData=function(){ console.log('getData方法') } // 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型 // 先保存当前方法 let onmethod=desc.value desc.value=function(...args:any[]){ // 接收参数 args=args.map(item=>{ return String(item) }) console.log(args) // ["123", "abc"],替换了原方法 onmethod.apply(this,args) // /api,执行原方法 } } } class HttpClient{ public urlApi:string |undefined constructor(){ this.urlApi='/api' } @logMethod('456') getData(){ console.log(this.urlApi) } } let http:any = new HttpClient(); http.getData(123,'abc')
4.方法参数装饰器:运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据;接收三个参数
第一个参数:对静态成员来说是类的构造函数,对实例成员来说是类的原型对象
第二个参数:方法的名字
第三个参数:参数在函数列表中的索引
// 参数装饰器 function logParams(params:any){ return function(target:any,methodName:any,paramsIndex:any){ console.log(params) // xxx,传入的参数 console.log(target) // {getData: ƒ, constructor: ƒ},原型对象 console.log(methodName) // getData,方法名称 console.log(paramsIndex) // 0,索引 target.apiUrl = params } } class HttpClient{ public urlApi:string | undefined constructor(){ } getData(@logParams('xxx') uuid:any){ } } let http:any = new HttpClient(); console.log(http.apiUrl) // xxx
装饰器执行顺序
多个同样的装饰器则先执行后面的装饰器
function logClass1(params?:string){ return function(target:any){ console.log('类装饰器1') } } function logClass2(params?:string){ return function(target:any){ console.log('类装饰器2') } } function logProprety(params?:any){ return function(target:any,attr:any){ console.log('属性装饰器') } } function logMethod(params?:any){ return function(target:any,methodName:any,desc:any){ console.log('方法装饰器') } } function logParams1(params?:any){ return function(target:any,methodName:any,paramsIndex:any){ console.log('方法参数装饰器1') } } function logParams2(params?:any){ return function(target:any,methodName:any,paramsIndex:any){ console.log('方法参数装饰器2') } } @logClass1() @logClass2() class HttpClient{ @logProprety() public urlApi:string | undefined constructor(){ } @logMethod() getData(@logParams1() uuid1:any,@logParams2() uuid2:any){ } } /*打印结果:
属性装饰器 方法参数装饰器2 方法参数装饰器1 方法装饰器 类装饰器2 类装饰器1*/
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。