简介
装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为。
使用@装饰器
需要把 tsconfig.json
的 experimentalDecorators
字段设置为 true
。
装饰器类型
在 TypeScript
里,主要有类装饰器、方法装饰器、属性装饰器、参数装饰器。
类装饰器
类装饰器定义在类上面。类装饰器运行是在类初始化的时候。
类装饰器的参数只有一个,参数是类本身。
比如,我们声明一个函数 addAge
去给 Class
的属性 age
添加年龄.
function addAge(constructor: Function) {
constructor.prototype.age = 18;
}
@addAge
class Person{
name: string;
age!: number;
constructor() {
this.name = 'randy';
}
}
let person = new Person();
console.log(person.age); // 18
所以这段代码实际上基本等同于:
Person = addAge(function Person() { ... });
constructor.prototype.age
就是在类原型上添加了age
属性并赋值18
。这样我们通过类Person
实例化出来的每个对象都会有age
属性,并且值为18
。
属性/方法装饰器
实际上一个Class
的属性/方法也可以被装饰,我们分别给 Person
类加上 say
和 run
方法。
属性/方法装饰器运行是在类初始化的时候。
// 声明装饰器修饰方法
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target);
console.log("prop " + propertyKey);
console.log("desc " + JSON.stringify(descriptor) + "\n\n");
descriptor.writable = false;
};
// 声明装饰器修饰属性
function prop(target: any, key: string): any {
console.log(target);
console.log("prop " + key);
const descriptor: PropertyDescriptor = {
writable: true,
configurable: true,
enumerable: true,
value: "jack",
};
return descriptor;
}
// 类
class Person{
@prop
name: string;
constructor() {
this.name = 'randy';
}
@method
say(){
return 'instance method';
}
@method
static run(){
return 'static method';
}
}
普通函数和静态函数参数是有区别的。
- 普通函数的装饰器接收的参数第一个是类的原型第二个是方法名第三个是修饰符。
static
函数的装饰器接收的参数第一个是类本身第二个是方法名第三个是修饰符。
属性的装饰器接收的参数第一个是类的原型第二个是属性名。
属性的装饰器可以返回属性描述符来描述该属性。
如果还不清楚Object
相关API
的可以看看笔者前面写的JS Object API详解这篇文章。
访问器属性getter或者setter同样可以用属性装饰器修饰,这里笔者就不再细说了。
参数装饰器
参数装饰器,顾名思义是用于修饰参数的装饰器。
function logParameter(target: Object, propertyKey: string, index: number) {
console.log(target, propertyKey, index);
}
class Person {
greet(@logParameter message: string, @logParameter name: string): string {
return `${message} ${name}`;
}
}
const p = new Person();
p.greet('hello', 'randy');
// Person { greet: [Function] } greet 1
// Person { greet: [Function] } greet 0
我们看到参数装饰器需要三个参数 target
、propertyKey
、index
:
- target —— 类的原型,也就是
Person.prototype
- propertyKey —— 参数的名称,上例中指的就是 greet
- index —— 参数数组中的位置,比如上例中参数 name 的位置是 1, message 的位置为 0
多个装饰器
一个类、属性、方法可以同时被多个装饰器修饰。
多个装饰器可以同时应用到一个声明上,就像下面的示例:
- 书写在同一行上:
@f @g x
- 书写在多行上:
@f
@g
x
在 TypeScript
里,当多个装饰器应用在一个声明上时执行顺序从下往上执行。
上面的例子会先运行@g
然后运行@f
。
装饰器执行顺序
当我们定义了属性装饰器、普通方法装饰器、参数装饰器、静态方法装饰器、类装饰器的时候这些装饰器的执行顺序是怎么样的呢?
装饰器的执行顺序总的来说先执行class
内部(属性、方法、参数)装饰器再执行类装饰器。这个顺序是固定的。
class
内部(属性、方法、参数)装饰器的执行顺序是不固定的,依赖你在class
内部的书写顺序。书写越靠前,越先执行。
当参数装饰器和方法装饰器同时定义在同一个方法上的时候,先执行参数装饰器再执行方法装饰器。
系列文章
TypeScript入门之类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名
后记
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!