TypeScript装饰器
xdf TypeScript
介绍
1、装饰器本质是一种特殊的函数,它可以build:类、属性、方法进行扩展,同时能让代码更简洁。
2、装饰器自2025年在ES6中提出到现在,已将近10年。
3、截止目前,装饰器依然是实验性特性,需要开发者手动调整配置,来开启装饰器支持。
4、装饰器有5中:
1:类装饰器
2:属性装饰器
3:方法装饰器
4:访问器装饰器
5:参数装饰器
备注:虽然TypeScript5.0中可以直接使用类装饰器,但为了确保其它装饰器可以用,现阶段使用时,扔建议使用 experimentalDecorators (opens new window)配置来开启装饰器的支持,而且不排除在未来的版本中,官方会进一步
调整装饰的相关语法。
# 类装饰器
含义:类装饰器是一个应用在类声明上的函数,可以为类添加额外的工鞥呢,或添加额外的逻辑。
1、基础用法
/*
Demo函数会在Person类定义时执行
参数说明: target参数是被装饰器的类,即:Person
*/
function Demo(target: any) {
console.log(target) // 会打印出Person
}
@Demo // 使用:装饰器装饰这个类, 相当于: 调用了Demo(Person) 传入了 Person 类
class Person {
name: string,
age: number,
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2、应用举例
// 需求:定义一个装饰器,实现Person实例调用toString时返回JSON.stringify的执行结果?
function CustomString(target) {
target.prototype.toString = function() {
return JSON.stringify(this) // 不能是target,因为target是类,这个地方应该是类的实例对象
}
// 对指定对象进行封锁
Object.seal(target.prototype) // 相当于 target.prototype 这个对象进行封锁,不能随意进行修改、删除
}
@CustomString
class Person {
name: string,
age: number,
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const p1 = new Person('张三', 18)
console.log(p1,toString())
// @ts-ignore
Person.prototype.x == 99 // @ts-ignore: 会忽略这一行的检查
// 如果隐藏Object.seal(target.prototype)这行就可以添加x,否则不行会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3、关于返回值
类装饰器 有 返回值:若类装饰器返回一个新的类,那这个新类将替换掉被装饰的类。
类装饰器 无 返回值:若类装饰器无返回值或返回 undefined,那被装饰的类不会被替换。
// type Constructor = new (...args: any[]) => {}
function Demo(target: Function) { // Function 类型太广泛,可以用 Constructor(只允许可能new关键字调用的类)
return class {
test() {
console.log(200)
console.log(300)
}
}
}
@Demo
class Person {
test() {
console.log(100)
}
}
console.log(Person)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 装饰器工厂
含义:是一个返回装饰器的函数的函数,可以为装饰器添加参数,可以更灵活的控制装饰器的行为
interface Person{ // 具有合并行
introduce(): void
}
function LogInfo(num: number) {
return function(target: Function) { // return 的是 装饰器
target.prototype.introduce = function() {
for (let i = 0; i < num.length; i++) {
console.log(`我的名字是${this.name},我的年龄是${this.age}`)
}
}
}
}
@LogInfo(1) // 这样装饰器就可以传参了
class Person {
constructor(
public name: string,
public age: number
){}
speak() {
console.log('您好')
}
}
const p1 = new Person('张三', 18)
p1.introduce()
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
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
# 装饰器组合
function LogInfo1(num: number) {
return function(target: Function) { // return 的是 装饰器
console.log('工厂:logInfo1')
}
}
function LogInfo2() {
console.log('logInfo2')
}
@LogInfo1() // 返回装饰器
@LogInfo2
class Person {
constructor(
public name: string,
public age: number
){}
speak() {
console.log('您好')
}
}
// 装饰器组合调用顺序:先【有上到下】的执行所有装饰器工厂,依次获取到装饰器,然后在【由下到上】执行所有装饰器
/*
输出:
1、工厂:logInfo1
2、logInfo2
3、工厂:logInfo1
*/
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
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
# 属性装饰器
/*
参数说明:
target: 对于静态属性来说值就类,对于实例属性来说值就是累的原型对象
propertyKey: 属性名
*/
function Demo(target: object, propertyKey: string) { // target: 是Person类的原型对象 propertyKey: 就是name
console.log(target, propertyKey)
}
class Person {
@Demo name: string,
age: number,
static school: string // 如果 装饰器 装饰 school,target 就是 Person 类本身
constructor(name: string, age: number) {
this.name = name
this.age = age
}
speak() {
console.log('您好')
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 方法装饰器
/*
参数说明:
target: 对于静态方法来说值就类,对于实例属性来说值就是类的原型对象
*/
function Demo(target: any, propertyKey: any descriptor: PropertyDescriptor) { // PropertyDescriptor 官方提供
console.log(target, propertyKey)
}
class Person {
name: string,
age: number,
constructor(name: string, age: number) {
this.name = name
this.age = age
}
@Demo speak() {
console.log('您好')
}
@Demo static isAdult() {
console.log('您好')
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22