装饰器

介绍

装饰器其实就是一个函数,通过注入的方式到类、方法、属性、参数上,拓展其功能。

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

所以,需要在tsconfig.json中开启兼容

1
"experimentalDecorators": true, 

装饰器使用语法如下:

1
2
3
4
5
function fun1() {
}

@fun1 // 等同于fun(Person1)
class Person1 {}

类装饰器

1
2
3
4
5
6
7
8
9
10
11
12
// 类装饰器
function fun1(target: any) {
// 这里的参数就是装饰的类
target.prototype.name = "lisi";
}

@fun1
class Person1 {}

let p1 = new Person1();
// @ts-ignore
console.log(p1.name);

这里的类装饰器不能传递参数,如果需要传参@fun1(arg),则需要使用装饰器工厂

装饰器工厂

其实就是返回一个函数,外面的函数用来接收参数,里面的函数用来就是一个装饰器。(函数柯里化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 装饰器工厂(可以传参)
function fun2(value: any) {
return function (target: any) {
target.prototype.username = value.username;
target.prototype.age = value.age;
};
}
@fun2({
username: "zhangsan",
age: 18,
})
class Person2 {}
let p2 = new Person2();
// @ts-ignore
console.log(p2.username, p2.age);

如果说同时使用了装饰器工厂和装饰器,那么它们的执行顺序不是从上到下的规律

装饰器组合

可以对同一个类使用多个装饰器和装饰器工厂。执行顺序如下:

  1. 执行所有的装饰器工厂,获取到装饰器
  2. 从下到上执行装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function demo1(target: any) {
console.log("demo1");
}
function demo2() {
console.log("demo2");
return (target: any) => {
console.log("demo2 into");
};
}
function demo3() {
console.log("demo3");
return (target: any) => {
console.log("demo3 into");
};
}
function demo4(target: any) {
console.log("demo4");
}
// 装饰器执行顺序
@demo1
@demo2()
@demo3()
@demo4
class Person3 {}

因此,打印结果如下:

1
2
3
4
5
6
demo2
demo3
demo4
demo3 into
demo2 into
demo1

属性装饰器

装饰属性

参数:

  1. 对于静态属性来说是类的构造函数,对于实例属性是类的原型对象
  2. 属性的名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 属性装饰器

function fun3(value: any) {
return function (target: any, propertyKey: any) {
target[propertyKey] = value;
// console.log(target); // Person4.prototype
};
}
class Person4 {
@fun3("wangwu")
// @ts-ignore
name: string;
}
let p4 = new Person4();
console.log(p4.name);

方法装饰器

方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。

方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 对于静态方法来说是类的构造函数,实例方法则是类的原型对象
  2. 方法名
  3. 方法的属性描述符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 方法装饰器
function fun4() {
return function (target: any, propertyKey: any, descriptor: any) {
// target[propertyKey] = value;
console.log(target, propertyKey, descriptor);
};
}

class Person5 {
@fun4()
// @ts-ignore
satName() {
console.log("say name");
}
}

打印结果:

1
2
3
4
5
6
{} satName {
value: [Function: satName],
writable: true,
enumerable: false,
configurable: true
}

参数装饰器

参数装饰器用来装饰参数

参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  2. 成员的名字
  3. 参数在函数参数列表中的索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function fun5(target: any, propertyKey: string, parameterIndex: number) {
console.log(target);
console.log("key " + propertyKey);
console.log("index " + parameterIndex);
};
class Person6 {
name: string;
constructor() {
this.name = 'junjie';
}
getName(@fun5 name: string){
return name
}
}
const user = new Person6();
user.name = 'user'
console.log(user.name)

输出结果:

1
2
3
4
{}
key getName
index 0
user