【TypeScript】何为装饰器

1.什么是装饰器

装饰器是一种特殊类型的声明,它能过被附加到类声明,方法,属性或者参数上,可以修改类的行为

通俗的来说就是一个方法,可以注入到类,方法,属性参数上来扩展类,属性,方法,参数的功能

2.装饰器的分类

  • 类装饰器
  • 属性装饰器
  • 方法装饰器
  • 参数装饰器

3.装饰器的写法:

  • 普通装饰器(无法传参)
  • 装饰器工厂(可以传参)

4.类装饰器

在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改类定义。

// 装饰器 (普通装饰器)
function logClass(params: any) {
    console.log(params)  // params就是当前类
    params.prototype.apiUrl = 'http://www.58.com' // 动态拓展属性
    params.prototype.run = function() {} // 动态扩展方法
}

@logClass
class HttpClient {
    constructor() {
        
    }
    
    getData() {
        
    }
}

var http: any = new HttpClient()
console.log(http.apiUrl) // http://www.58.com

// 装饰器(装饰器工厂)
function logClass(params: string) {
    return function(target: any) { // target 就是当前类
        console.log(target)
        console.log(params)
    }
    target.prototype.apiUrl = params
}

@logClass2('http://www.58.com')
class HttpClient {
    constructor() {
        
    }
    
    getData() {
        
    }
}
// 装饰器应用例子---重载类的属性方法
function logClass3(target: any) {
    return class exntends target {
        apiUrl: any = '我是修改后的数据'
        getData() {
            console.log('----'+this.apiUrl)
        }
    }
}

@logClass3
class HttpClient {
    public apiUrl: string | undefined
    constructor() {
        this.apiUrl = '初始值'
    }
    
    getData() {
        console.log(this.apiUrl)
    }
}

var http:any = new HttpClient()
http.getData() // ----我是修改后的数据

5.属性装饰器

function logProperty(params: any) {
    return function(target: any, attr: any) {
        console.log(target) // 当前对象
        console.log(attr) // 属性名称 打印了url
        target.attr = params;
    }
}

class HttpClient {
    @logProperty('http://www.58.com')
    public url: any | undefined
    constructor() {
        
    }
    
    getData() {
        console.log(this.url)
    }
}

var http = new HttpClient()
http.getData() // http://www.58.com

6.方法装饰器

它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义

方法装饰会在运行时传入3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
  • 成员的名字
  • 成员的属性描述符
function get(params: any) {
    return function(target: any, methodName: any, desc: any) {
        console.log(target) // 原型对象 HttpClient对象(这个例子中)
        console.log(methodName) // 方法名称 getData
        console.log(desc) // 方法里的描述信息
        
        target.apiUrl = 'xxx' // 修改值
        target.run = function() { // 拓展方法
            console.log('run')
        }
        
        // 修改装饰器的方法 把修饰器方法里面传入的所有参数改为string类型
        // 1. 保存当前的方法
        var oMethod = desc.value;
        desc.value = function(...args: any[]) {
            args = args.map((value) => {
                return String(value)
            })
            console.log(args)
            
            // 修改方法
            oMthod.apply(this, args)
        }
    }
}

class HttpClient {
    public url: any | undefined
    constructor() {
        
    }
    @get('http://www.58.com')
    getData(...args: any[]) {
        console.log(this.url)
    }
}

var http = new HttpClient()
console.log(http.apiUrl)
http.run()

7.方法参数装饰器

参数装饰器表达式会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 参数的名字
  • 参数在函数参数列表中的索引
function logParams(params: any) {
    return function(target: any, methodName: any, paramsIndex: any) {
        console.log(target) // 原型对象
        console.log(methodName) // getData
        console.log(paramsIndex) // 0
        console.log(params) // xxx
        
        target.url = params
    }
}

class HttpClient {
    public url: any | undefined
    constructor() {
        
    }
    
    getData(@logParams('xxx') uuid: any) {
        console.log(uuid) // 123456
    }
}

var http = new HttpClient()
http.getData(123456) 

8.装饰器执行顺序

属性》方法》方法参数》类
如果有多个同样的装饰器,会先执行后面的

// 伪代码
...
@logClass1('类装饰器1')
@logClass2('类装饰器2')
class HttpClient {
    @logAttribute('属性装饰器')
    public url: string
    
    @logMethod('方法装饰器')
    constructor() {}
    
    getData(@logParam1('参数装饰器1') attr1: any, @logParam2('参数装饰器2') attr2: any) {}
}


// 属性参数器
// 方法装饰器
// 参数装饰器2
// 参数装饰器1
// 类装饰器2
// 类装饰器1


posted @ 2019-08-11 20:27  林璡  阅读(189)  评论(0编辑  收藏  举报