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