一、概述
1、装饰器定义
- 它是一个表达式
- 该表达式被执行后,返回一个函数
- 函数的入参分别为 target、name 和 descriptor
- 执行该函数后,可能返回 descriptor 对象,用于配置 target 对象
2、装饰器分类
1)根据装饰器的位置
- 类装饰器
- 函数装饰器
- 属性装饰器
- 参数装饰器 2)根据装饰器是否有参数
- 无参装饰器(一般装饰器)
- 有参装饰器(装饰器工厂)
二、装饰器的参数说明及应用
1. 类装饰器
类装饰声明
declare type ClassDecorator = <TFunction extends Function>(
target: TFunction
) => TFunction | void;
参数说明: target: Object - 被装饰的类
示例1:无参数
function logClass (target: any) {
console.log('hello world')
}
@logClass
class Greeting {
constructor() {}
}
示例2: 有参数
function logClass (params: any) {
return function (target: any) {
target.prototype.say = function () {
console.log(params)
}
}
}
@logClass('hello ts')
class Greeting {
constructor() {}
}
var greet: any = new Greeting()
greet.say()
2. 函数装饰器
方法装饰声明
declare type MethodsDecorator = (target:Object, propertyKey: string | symbol ) => void;
方法装饰器顾名思义,用来装饰类的方法,参数说明:
- target: Object - 被装饰的类
- propertyKey: string | symbol - 方法名
- descriptor: TypePropertyDescript - 属性描述符
示例:将类中的方法的参数类型全部转化成string类型
function logMethod (target: any, methodName: any, desc: any) {
const methods = desc.value // 保存当前方法
desc.value = function (...args: any[]) {
args = args.map(item => String(item))
methods.apply(this, args)
}
}
class Greeting {
userName: string | undefined
@logMethod
getData (name: string, age: number) {
console.log('change after:', typeof name, typeof age)
}
}
var greet = new Greeting()
greet.getData('张三', 30)
3. 属性装饰器
属性装饰声明
declare type PropertyDecorator = (target:Object, propertyKey: string | symbol ) => void;
属性装饰器顾名思义,用来装饰类的属性。它接收两个参数
- target: Object - 被装饰的类
- propertyKey: string | symbol - 被装饰类的属性名
示例:给类的中属性设置指定一个默认值
function logProperty (params: any) {
return function (target: any, propertyName: any) {
target[propertyName] = params
}
}
class Greeting {
@logProperty('张三')
userName: string | undefined
getData () {
return this.userName
}
}
var greet: any = new Greeting()
console.log(greet.userName) // 张三
4. 参数装饰器
参数装饰器声明:
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol,
parameterIndex: number ) => void
参数装饰器顾名思义,是用来装饰函数参数,它接收三个参数:
- target: Object - 被装饰的类
- propertyKey: string | symbol - 方法名
- parameterIndex: number - 方法中参数的索引值
示例:
function logParams(params: any) {
return function (target: any, key: any, value: any) {
console.log(key)
console.log(value)
}
}
class Greeting {
name: string | undefined
say (@logParams(20) age?: number) {
return age
}
}
var h = new Greeting()
console.log(h.say())
三、执行顺序
function logClass1(target: any) {
console.log('类装饰器1')
}
function logClass2(target: any) {
console.log('类装饰器2')
}
function logMethod(target: any, methodName: any, desc: any) {
console.log('函数装饰器')
}
function logProperty (target: any, propertyName: any) {
console.log('属性装饰器')
}
function logParam1 (target: any, key: any, index: any) {
console.log('参数装饰器1')
}
function logParam2 (target: any, key: any, index: any) {
console.log('参数装饰器2')
}
@logClass1
@logClass2
class Greeting {
@logProperty
userName: string | undefined
@logMethod
getData () {
return this.userName
}
say (@logParam1 name: string, @logParam2 age: number) {
console.log('hello world')
}
}
输出的结果是: 属性装饰器》参数装饰器2 》参数装饰器1 》函数装饰器 》类装饰器2 》类装饰器1
结论:
- 如果同时存在多个装饰器,者是从后往前执行的
- 各类的装饰器的执行顺序是:属性装饰器 》参数装饰器》函数装饰器 》类装饰器