浅析TypeScript装饰器(decorators)

一、什么是装饰器

  装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。

  装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

  通俗的理解可以认为就是在原有代码外层包装了一层处理逻辑。个人认为装饰器是一种解决方案,而并非是狭义的@Decorator,后者仅仅是一个语法糖罢了。

  装饰器在身边的例子随处可见,一个简单的例子:水龙头上装起泡器,把空气混入水流中,很多泡泡在水里。但是安装起泡器对水龙头本身并没有什么影响,即使拆掉起泡器,水龙头也能照样工作。水龙头的作用在于阀门的控制,至于水中掺不掺气泡不是水龙头需要关心的。相当于就是给水龙头增加一个附加功能。

1、为什么要用装饰器

  有些时候,我们会对传入参数的类型判断、对返回值的排序、过滤,对函数添加节流、防抖或其他的功能性代码,基于多个类的继承,各种各样的与函数逻辑本身无关的、重复性的代码。所以,对于装饰器,可以简单地理解为是非侵入式的行为修改

2、如何定义装饰器

  装饰器本身其实就是一个函数,理论上忽略参数的话,任何函数都可以当做装饰器使用。

// helloword.ts
function helloWord(target: any) {
    console.log('hello Word!');
}
@helloWord
class HelloWordClass {
    // ......
}

3、装饰器组合:多个装饰器可以同时应用到一个声明上,就像下面的示例:

// 书写在同一行上:
@f @g x

// 书写在多行上:
@f
@g
x

二、装饰器执行时机

  修饰器对类的行为的改变,是代码编译时发生的(不是TypeScript编译,而是js在执行机中编译阶段),而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数。在Node.js环境中模块一加载时就会执行。

  但是实际场景中,有时希望向装饰器传入一些参数,如下:

@Path("/hello", "world")
class HelloService {}

  此时上面装饰器方法就不满足了(VSCode编译报错),这是我们可以借助JavaScript中函数柯里化特性

function Path(p1: string, p2: string) {
    return function (target) { //  这才是真正装饰器
        // do something 
    }
}

三、装饰器类型

  装饰器的类型有:类装饰器、访问器装饰器、属性装饰器、方法装饰器、参数装饰器,但是没有函数装饰器(function)。

 

 

           

 

上一篇:Day167/200 自动执行TypeScript和interface、type 区别


下一篇:我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。