装饰器

Decorator 装饰器是一项实验性特性,在未来的版本中可能会发生改变

它们不仅增加了代码的可读性,清晰地表达了意图

而且提供了一种方便的手段,增加或修改类的功能

若要启用实验性的装饰器特性,必须在命令行或tsconfig.json里启用编译器选项

1
2
"experimentalDecorators": true,
"emitDecoratorMetadata": true

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上

类装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// target:类的构造器
const Base:ClassDecorator = (target)=> {
console.log(target)
// 可以不破坏类内部代码块结构而增加属性和方法
target.prototype.__yajue = "yjsp"
target.prototype.fn = ()=> {
console.log("24岁,是学生")
}
}

// 编译阶段就会调用这个函数,无需手动调用
@Base
class Http {}

// Base(Http) // 和在类声明前使用@Base是等价的

const http = new Http() as any
console.log(http.__yajue) // -> "yjsp"
http.fn()

装饰器工厂

使用函数柯里化,就能给装饰器传自定义参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const Base = (str:string) => {
const fn: ClassDecorator = (target) => {
console.log(target)
target.prototype.name = str
target.prototype.fn = () => {
console.log("24岁,是学生")
}
}
return fn
}

@Base("yajue")
class Http { }

let http = new Http() as any
console.log(http.name) // ->"yajue"

装饰器组合

可以同时使用多个装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const Base = (str:string) => {
const fn: ClassDecorator = (target) => {
console.log(target)
target.prototype.name = str
target.prototype.fn = () => {
console.log("24岁,是学生")
}
}
return fn
}
const Omg = (target)=> {
target.prototype.age = 24
}

@Base("yajue")
@Omg
class Http { }

let http = new Http() as any
console.log(http.name) // ->"yajue"
console.log(http.age) // ->24

方法装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import axios from "axios"

const Get = (url:string)=> {
// target:原型对象 key:方法名 descriptior:描述符
const fn:MethodDecorator = (target,key,descriptor: PropertyDescriptor)=> {
axios.get(url).then(res=>{
// 函数体
descriptor.value(res.data)
})
}
return fn
}

class Http {
@Get("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList(data:any) {
console.log(data.result.list)
}
}

参数装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import axios from "axios"
import "reflect-metadata"

const Get = (url:string)=> {
// target:原型对象 _:方法名 descriptior:描述符
const fn:MethodDecorator = (target,_,descriptor: PropertyDescriptor)=> {
const key = Reflect.getMetadata("key",target)
axios.get(url).then(res=>{
// 函数体
descriptor.value(key? res.data[key]: res.data)
})
}
return fn
}

const Result = ()=> {
// target:原型对象 key:方法名 index:参数所在位置
const fn:ParameterDecorator = (target,key,index)=> {
// 参数装饰器优先于方法装饰器,所以这里使用元数据
Reflect.defineMetadata("key","result",target)
}
return fn
}

class Http {
@Get("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList(@Result() data:any) {
console.log(data)
}
}

属性装饰器

1
2
3
4
5
6
7
8
9
10
11
12
// target:原型对象   key:属性名
const Name:PropertyDecorator = (target,key)=> {
console.log(target,key)
}

class Http {
@Name
yajue:string
constructor(yajue:string) {
this.yajue = yajue
}
}