# 装饰器
装饰器是一种针对class类的特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。通俗来讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能,在你上面声明一个符号,我通过这个符号来控制你。就像是封装一个函数,只需要知道结果,具体要做什么不用问,通过装饰器来完成,完成后把结果给到被装饰的就行。
常见的装饰器有: 类装饰器、方法装饰器、参数装饰器、属性装饰器
所有装饰器执行顺序: 属性》方法》方法参数》类,如果多个同类型装饰器 会先执行后面的
用在谁上面就装饰谁,放在类上面就针对整个类装饰,放在类的属性上面,就针对这个属性修饰,放在方法上面就针对这个方法,每种修饰都有不同的写法。
要使用装饰器,需要开启配置 experimentalDecorators: true
和 emitDecoratorMetadata: true
,定义装饰首字母一般大写。
# 类装饰器
放在类前面,来监视、修改或替换类定义
普通类装饰器(不能传参)
// 默认接收一个参数target,target为当前类的构造函数
// 通过target可以更改原型上的属性和方法
const Base:ClassDecorator = (target) => {
console.log(target); // ƒ HttpClient() {} target就是当前类 HttpClient
target.prototype.url = '动态扩展的属性'
target.prototype.run = function() {
console.log('动态添加方法')
}
}
@Base
class HttpClient {
constructor() {}
getData() {}
}
let http = new HttpClient()
console.log(http.url) // 动态扩展的属性
http.run()
装饰器工厂(可传参)
// 通过return一个函数来传入参数
const Base = (name: string) => {
const fn: ClassDecorator = (target) => {
target.prototype.name = name
target.prototype.run = function() {
console.log('动态添加方法')
}
}
return fn
}
@Base('zhangsan')
class HttpClient {
constructor() {}
getData() {
}
}
let http = new HttpClient();
console.log(http.name)
http.run();
重载类里面的属性和方法
function Base(target:any) {
return class extends target {
url:string = '我是修改后的url';
getData():void {
this.url = this.url+'xxxxxxxxxxx'
console.log(this.url)
}
}
}
@Base
class HttpClient {
url:string | undefined
constructor() {
this.url = '我是构造函数中的url'
}
getData() {
console.log(this.url)
}
}
let http = new HttpClient3();
console.log(http.url)
http.getData();
# 属性装饰器
属性装饰器表达式会在运行时当做函数被调用,传入两个参数:
- 1、对于静态成员来说是类的构造函数,对于实力成员是类的原型对象
- 2、属性的名字
// 属性装饰器
const Property = (newUrl: string) => {
const fn: PropertyDecorator = (target:any, attr:any) => {
console.log(target) // {getData: ƒ, constructor: ƒ} 类的原型对象
console.log(attr) // url 类的属性
// 扩展或者修改属性
target[attr] = newUrl
target.test = 'hahahahahahah'
}
return fn
}
class HttpClient {
@Property('http://www.tourboxtech.com')
url: string | undefined
constructor() {
}
getData() {
console.log(this.url)
}
}
let http = new HttpClient();
console.log(http.test); // hahahahahahah 装饰器扩展的属性
http.getData(); // http://www.tourboxtech.com 装饰器修改的属性
# 方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义,传入三个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 2、成员的名字、
- 3、成员的属性描述
// 方法装饰器
const Method = (newUrl: string) => {
const fn:MethodDecorator = (target: any, methodName: any, descriptor: PropertyDescriptor) => {
console.log(target) // {getData: ƒ, constructor: ƒ} 类的原型对象
console.log(methodName) // getData 方法名
console.log(descriptor) // 描述
console.log(descriptor.value) // 类的方法
// 扩展或者修改属性和方法
target.url = newUrl
target.test = 'http://www.xxxx.com'
target.run = function() {
console.log(this.url)
}
// 修改类的方法,重新赋值一个方法就行了
descriptor.value = () => {
console.log(target.test)
}
}
return fn
}
class HttpClient {
url:string | undefined
constructor() {
}
@Method('hello')
getData() {
console.log(this.url)
}
}
let http = new HttpClient()
http.run(); // hello 装饰器扩展的方法
http.getData(); // http://www.xxxx.com 装饰器修改原方法
# 方法参数装饰器
它会被应用到方法的参数上,可以为原型增加一些元素数据,传入三个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 2、方法的名字
- 3、参数在函数参数列表的索引
// 方法参数装饰器
const Params = (params: any) => {
console.log(params) // 装饰器传入的参数
const fn: ParameterDecorator = (target: any, propertyKey: any, parameterIndex: number) => {
console.log(target) // {getData: ƒ, constructor: ƒ} 类的原型对象
console.log(propertyKey) // getData 方法名
console.log(parameterIndex) // 0 索引
target.test = params
}
return fn
}
class HttpClient {
url:string | undefined
constructor() {
}
getData(@Params('我是参数') uuid:any) {
console.log(uuid)
}
}
let http = new HttpClient();
http.getData(12233);
http.test;