装饰器概念
ts官方文档上,是这样描述装饰器的,装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能
装饰器主要有以下几种:
类装饰器
类装饰器是应用于类的装饰器,可以进行类的原型修改和重写属性方法等操作
参数: target:类
// 类装饰器
function boyDecorator(target: any) {
// 动态扩展类的原型
target.prototype.name = 'lucky';
target.prototype.sayHi = function (): void {
console.log('你好啊!')
}
}
@boyDecorator
class Boy { }
console.log(Boy.prototype) // { name: 'lucky', sayHi: [Function (anonymous)] }
装饰器工厂
如果我们要定制一个装饰器如何应用到一个声明上,我们得写一个装饰器工厂函数。 装饰器工厂就是一个简单的函数,它本质就是返回一个装饰器,以供装饰器在运行时调用,上面的装饰器写成装饰器工厂
// 类装饰器工厂
function boyDecorator(params: string) {
return function (target: any) {
console.log(params) // 再见
target.prototype.name = 'lucky';
target.prototype.sayHi = function (): void {
console.log('你好啊!' + params)
}
}
}
@boyDecorator('再见') // 传入相应规则的参数
class Boy { }
console.dir(Boy.prototype) // { name: 'lucky', sayHi: [Function (anonymous)] }
属性装饰器
属性装饰器应用于属性中
参数: target:类,propertyKey:属性名
// 属性装饰器
function attrDecorator(params: string) {
return function (target: any, name: string) {
// console.log(params)
target[name] = params // 给属性赋值'lucky'
}
}
class Boy {
@attrDecorator('lucky')
public name: string | undefined
}
const me = new Boy()
console.log(me.name) // lucky
方法装饰器
属性装饰器应用于方法中,方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
propertyKey:成员的名字
descriptor:成员的属性描述符(可以用来改变方法本身)
// 方法装饰器
function fnDecorator(params: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(descriptor) /* {
value: [Function (anonymous)], // 对象本身
writable: true, // 属性值可改性
enumerable: true, // 可遍历性
configurable: true // 对象可改性
} */
console.log(params) // 我被改了
// 修改方法本身
descriptor.value = function (): string {
return params
}
}
}
class Boy {
public name: string = 'lucky'
@fnDecorator('我被改了')
getName(): string {
return this.name
}
}
const me = new Boy()
console.log(me.getName()) // 我被改了
参数装饰器
参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。
参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数
target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
propertyKey:方法的名字
parameterIndex:参数在方法参数列表中的索引
// 参数装饰器
function paramsDecorator() {
return function (target: any, propertyKey: string | undefined, parameterIndex: number) {
console.log(target) // { getName: [Function (anonymous)] }
console.log(propertyKey) // getName
console.log(parameterIndex) // 0
}
}
class Boy {
public name: string = 'lucky'
getName(@paramsDecorator() age: number) {
return this.name + age
}
}
const me = new Boy()
console.log(me.getName(12)) // lucky12
访问器装饰符
访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义
访问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
target: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
propertyKey: 成员的名字
descriptor:成员的属性描述符
function configDecorator(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value; // 改变对象的可配置性
};
}
class Boy {
private _name: number;
private _age: string;
constructor(name: number, age: string) {
this._name = name;
this._age = age;
}
@configDecorator(false)
get name() { return this._name; }
@configDecorator(false)
get age() { return this._age; }
}
执行顺序
类中不同声明上的装饰器将按以下规定的顺序应用:
参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个实例成员。
参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个静态成员。
参数装饰器应用到构造函数。
类装饰器应用到类。