TS 装饰器
大约 2 分钟
装饰器(Decorator)是一种语法结构,用来在定义时修改类(class)的行为。
在语法上,装饰器有如下几个特征。
(1)第一个字符(或者说前缀)是@
,后面是一个表达式。
(2)@
后面的表达式,必须是一个函数(或者执行后可以得到一个函数)。
(3)这个函数接受所修饰对象的一些相关值作为参数。
(4)这个函数要么不返回值,要么返回一个新对象取代所修饰的目标对象。
一般类有四个装饰器:
@frozen
class Foo {
@configurable(false)
@enumerable(true)
method() {}
@throttle(1000)
expensiveMethod() {}
}
一个用在类本身(@frozen
),另外三个用在类的方法(@configurable
、@enumerable
、@throttle
)。
执行顺序
装饰器的执行分为两个阶段。
(1)评估(evaluation):计算@
符号后面的表达式的值,得到的应该是函数。
(2)应用(application):将评估装饰器后得到的函数,应用于所装饰对象。
也就是说,装饰器的执行顺序是,先评估所有装饰器表达式的值,再将其应用于当前类。应用装饰器时,顺序依次为方法装饰器和属性装饰器,然后是类装饰器。
应用实例:
function d(str: string) {
console.log(`评估 @d(): ${str}`)
return (value: any, context: any) => console.log(`应用 @d(): ${str}`)
}
function log(str: string) {
console.log(str)
return str
}
@d('类装饰器')
class T {
@d('静态属性装饰器')
static staticField = log('静态属性值');
@d('原型方法')
[log('计算方法名')]() {}
@d('实例属性')
instanceField = log('实例属性值')
}
理想输出:
// "评估 @d(): 类装饰器"
// "评估 @d(): 静态属性装饰器"
// "评估 @d(): 原型方法"
// "计算方法名"
// "评估 @d(): 实例属性"
// "应用 @d(): 原型方法"
// "应用 @d(): 静态属性装饰器"
// "应用 @d(): 实例属性"
// "应用 @d(): 类装饰器"
// "静态属性值"
但是经过笔者测试用 deno 运行后结果为:
计算方法名
静态属性值
评估 @d(): 静态属性装饰器
应用 @d(): 静态属性装饰器
评估 @d(): 原型方法
应用 @d(): 原型方法
评估 @d(): 实例属性
应用 @d(): 实例属性
评估 @d(): 类装饰器
应用 @d(): 类装饰器
原因可为 deno 采用的是旧版 typescript 编译器,而旧版编译器在评估装饰器时,会先将装饰器应用到当前类,然后再评估表达式。
参考文件
Loading...