理解装饰器的执行顺序对于正确使用装饰器至关重要。不同类型的装饰器有不同的执行顺序,多个装饰器的组合也有特定的执行规则。
当使用装饰器工厂时,工厂函数按从上到下的顺序执行,而装饰器本身按从下到上的顺序执行。
function first() {
console.log("first(): 工厂")
return function (target: any) {
console.log("first(): 装饰器")
}
}
function second() {
console.log("second(): 工厂")
return function (target: any) {
console.log("second(): 装饰器")
}
}
@first()
@second()
class MyClass {}
输出:
first(): 工厂
second(): 工厂
second(): 装饰器
first(): 装饰器
类成员装饰器按以下顺序执行:
function methodDecorator() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("方法装饰器")
}
}
function propertyDecorator() {
return function (target: any, propertyKey: string) {
console.log("属性装饰器")
}
}
function paramDecorator() {
return function (target: any, propertyKey: string, parameterIndex: number) {
console.log("参数装饰器")
}
}
class Example {
@propertyDecorator()
name: string = ""
@methodDecorator()
greet(@paramDecorator() name: string): string {
return `你好,${name}`
}
}
输出:
参数装饰器
方法装饰器
属性装饰器
完整的装饰器执行顺序:
function classDecorator() {
return function (target: any) {
console.log("类装饰器")
}
}
function methodDecorator(name: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`方法装饰器: ${name}`)
}
}
function propertyDecorator(name: string) {
return function (target: any, propertyKey: string) {
console.log(`属性装饰器: ${name}`)
}
}
function paramDecorator(name: string) {
return function (target: any, propertyKey: string, parameterIndex: number) {
console.log(`参数装饰器: ${name}`)
}
}
@classDecorator()
class Example {
@propertyDecorator("实例属性")
instanceProp: string = ""
@methodDecorator("实例方法")
instanceMethod(@paramDecorator("实例参数") param: string) {}
@propertyDecorator("静态属性")
static staticProp: string = ""
@methodDecorator("静态方法")
static staticMethod(@paramDecorator("静态参数") param: string) {}
constructor(@paramDecorator("构造函数参数") param: string) {}
}
输出:
参数装饰器: 实例参数
方法装饰器: 实例方法
属性装饰器: 实例属性
参数装饰器: 静态参数
方法装饰器: 静态方法
属性装饰器: 静态属性
参数装饰器: 构造函数参数
类装饰器
同一成员上的多个装饰器,工厂函数从上到下执行,装饰器从下到上执行。
function decorator(name: string) {
console.log(`${name}: 工厂`)
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`${name}: 装饰器`)
}
}
class Example {
@decorator("A")
@decorator("B")
@decorator("C")
method() {}
}
输出:
A: 工厂
B: 工厂
C: 工厂
C: 装饰器
B: 装饰器
A: 装饰器
方法装饰器可以形成调用链,外层装饰器先执行。
function log(prefix: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value
descriptor.value = function (...args: any[]) {
console.log(`${prefix}: 开始`)
const result = original.apply(this, args)
console.log(`${prefix}: 结束`)
return result
}
return descriptor
}
}
class Example {
@log("A")
@log("B")
method() {
console.log("执行方法")
}
}
const example = new Example()
example.method()
输出:
A: 开始
B: 开始
执行方法
B: 结束
A: 结束
理解执行顺序对于实现复杂功能很重要。
function validate() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("验证装饰器")
return descriptor
}
}
function cache() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("缓存装饰器")
return descriptor
}
}
function log() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("日志装饰器")
return descriptor
}
}
class DataService {
@log()
@cache()
@validate()
fetchData(id: number) {
console.log("获取数据")
return { id, data: "数据" }
}
}
const service = new DataService()
service.fetchData(1)
执行顺序:验证 -> 缓存 -> 日志
装饰器工厂函数从上到下执行,装饰器本身从下到上执行。类成员装饰器按参数装饰器、方法/属性装饰器的顺序执行。实例成员装饰器先于静态成员装饰器执行。构造函数参数装饰器在类装饰器之前执行。理解装饰器执行顺序对于正确组合装饰器至关重要。