介绍
装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。 Javascript里的装饰器目前处在 建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。
注意 装饰器是一项实验性特性,在未来的版本中可能会发生改变。
若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json
里启用experimentalDecorators
编译器选项:
命令行:
1 | tsc --target ES5 --experimentalDecorators |
tsconfig.json:
1 | { |
使用
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为。 装饰器使用 @expression
这种形式,expression
求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
例:
1 | '/hello') ( |
如何定义装饰器
装饰器本身其实就是一个函数,理论上忽略参数的话,任何函数都可以当做装饰器使用。例:
demo.ts
1 | function Path(target:any) { |
使用tsc
编译后,执行命令node demo.js
,输出结果如下:
1 | I am decorator. |
装饰器执行时机
修饰器对类的行为的改变,是代码编译时发生的(不是TypeScript编译,而是js在执行机中编译阶段),而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数。
在Node.js环境中模块一加载时就会执行
函数柯里化解决参数问题
但是实际场景中,有时希望向装饰器传入一些参数, 如下:
1 | "/hello", "world") ( |
此时上面装饰器方法就不满足了(VSCode编译报错),这是我们可以借助JavaScript中函数柯里化特性
1 | function Path(p1: string, p2: string) { |
五种装饰器
在TypeScript中装饰器可以修饰四种语句:类,属性,访问器,方法以及方法参数。
1 类装饰器
应用于类构造函数,其参数是类的构造函数。
注意class
并不是像Java那种强类型语言中的类,而是JavaScript构造函数的语法糖。
1 | function Path(path: string) { |
2 方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、成员的名字。
- 3、成员的属性描述符。
1 | function GET(url: string) { |
注意:在vscode编辑时有时会报作为表达式调用时,无法解析方法修饰器的签名。
错误,此时需要在tsconfig.json中增加target配置项:
1 | { |
3 方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、参数的名字。
- 3、参数在函数参数列表中的索引。
1 | function PathParam(paramName: string) { |
4 属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、成员的名字。
1 | function DefaultValue(value: string) { |
装饰器加载顺序
1 | function ClassDecorator() { |
输出结果:
1 | I am property decorator |
从上述例子得出如下结论:
1、有多个参数装饰器时:从最后一个参数依次向前执行
2、方法和方法参数中参数装饰器先执行。
3、类装饰器总是最后执行。
4、方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会一直紧紧挨着方法执行。上述例子中属性和方法调换位置,输出如下结果:
1 | I am parameter2 decorator |