购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.1 贯穿全书的装饰器

本节首先介绍装饰器(Decorator)的基本概念和常见的5种装饰器类型,包括类装饰器、方法装饰器、属性装饰器、参数装饰器和访问器装饰器。接着介绍Nest中常用的装饰器,我们先初步认识它们。

3.1.1 基本概念

顾名思义,装饰器(Java中有个类似的概念叫注解)是用来装饰和扩展对象功能的。它能够在不改变原有对象结构的前提下,增加额外的功能,以满足更多的实际需求。

举个例子:一间房子里放了一张床,就满足了基本的居住需求。在此基础上,如果新增了沙发、红酒杯、电视机,那么就不仅能够满足休息的需求,还能提供娱乐和休闲的体验。在这个比喻中,沙发、红酒杯、电视机就像是装饰器,它们可以在不影响基本功能的前提下,根据需要随意添加或移除,从而实现功能的扩展和松耦合。

3.1.2 装饰器的种类

上例中,沙发、红酒杯、电视机属于不同的装饰器,它们实现了不同的功能。同样地,常用的装饰器也分为以下几种:

(1)类装饰器。

(2)方法装饰器。

(3)属性装饰器。

(4)参数装饰器。

(5)访问器装饰器。

尽管装饰器仍处于提案(stage-3)阶段,但它们已经广泛应用于TypeScript和Babel编译中。以方法装饰器为例,在stage-3提案中的实现如下:

上述代码中定义了一个Log方法装饰器,用于修饰类方法,其中target是被修饰的对象,context提供上下文信息。在基于TypeScript构建的Nest项目中,采用的是stage-1提案的装饰器版本,具体如下:

     /**
       * 方法装饰器
       */
     const log: MethodDecorator = (
       target: Function,
       propertyKey: string | Symbol,
       descriptor: PropertyDescriptor
     ) => {
       // 此处编写你的逻辑
     };

上述代码中,Log方法装饰器接收3个参数:target是被修饰的值,propertyKey是被修饰的属性键(方法名),description是被装饰的方法的属性描述符对象。

下面通过简单的示例分别进行介绍。

1.类的装饰

装饰器可以用来装饰整个类,以此增强类的功能,示例代码如下:

在上面的代码中,@doc用来装饰App类,同时往原型链上添加一个属性name,target是被修饰的类。

我们通过CodePen来编译ES6代码。CodePen是一个社区驱动的在线代码编辑器,支持编辑HTML、CSS和JavaScript。CodePen还支持Babel,这使得它能够将ES6代码转换成ES5并进行实时预览。

由于本节案例中我们使用TypeScript编码,因此需要在CodePen中找到Settings下的JS选项,并将JavaScript Preprocessor(JavaScript预处理器)设置为TypeScript,如图3-1所示。

图3-1 设置CodePen预处理器

保存后,类装饰器执行结果如图3-2所示。

图3-2 类装饰器的执行结果

上面打印了代码预期的结果,成功地给实例添加了属性name,并获取了App的构造函数,这样我们就可以动态地修改类的属性和行为了。

如果觉得一个target参数不够用,怎么办呢?可以通过工厂函数来增强装饰器的能力。代码如下:

通过工厂函数增强装饰器的能力后,@doc可以接收外部参数,使得App被实例化时能够获取更多的信息来组织代码,具体效果如图3-3所示。

图3-3 装饰器工厂

至此,你应该已经理解了Nest中的装饰器的实现方式,它在依赖注入中扮演着重要的角色。然而,请不要急于下结论,让我们继续深入探讨。

2.方法的装饰

装饰器可以用来装饰类的方法,代码如下:

在上面的代码中,@Log装饰器函数修饰了User类的getName方法。其中,target是被“装饰”的类的原型,即User.prototype。由于此时类还没有被实例化,因此只能装饰原型对象。这与类装饰器有所不同。运行结果如图3-4所示。

图3-4 方法装饰器的运行结果

由于User类的原型尚未附加属性方法,因此是空对象{}。

3.属性的装饰

装饰器也可以用来装饰类的属性,代码如下:

在上面的代码中,@prop用于装饰User类的name属性。此时,target是被装饰的类的原型对象,propertyKey是被修饰的属性名。具体的运行结果如图3-5所示。

图3-5 属性装饰器的运行结果

4.参数的装饰

除了装饰类、类方法和类属性外,装饰器还能装饰类方法的参数,示例代码如下:

在上述代码中,@Param用于装饰类方法getName的参数,其中target是被装饰类的原型,propertyKey是被装饰的类方法,index是装饰方法参数的索引位置。具体的运行结果如图3-6所示。

图3-6 参数装饰器的运行结果

5.访问器的装饰

装饰器还可以用来修饰类的访问器,即属性的getter方法。示例代码如下:

访问器装饰器与类方法装饰器类似,唯一的区别在于它们的描述符(descriptor)中某些键(key)不同。

方法装饰器的描述器键包括:

● value

● writable

● enumerable

● configurable

访问器装饰器的描述器的key为:

● get

● set

● enumerable

● configurable

运行结果如图3-7所示。

图3-7 访问器装饰器的运行结果

了解了这几个装饰器的概念后,接下来学习Nest中的装饰器,你应该能够轻松理解。

3.1.3 Nest中的装饰器

在Nest中实现了前面列举的前4种装饰器,它们包含但不限于:

● 类装饰器:@Controller、@Injectable、@Module、@UseInterceptors。

● 方法装饰器:@Get、@Post、@UseInterceptors。

● 属性装饰器:@IsNotEmpty、@IsString、@IsNumber。

● 参数装饰器:@Body、@Param、@Query。

下面分别对它们进行解释。

● @Controller():用于装饰控制器类,使之能够管理应用中的路由程序,并通过设置路由路径前缀来模块化管理路由。

● @Injectable():装饰后成为服务提供者,可以被其他对象进行依赖注入。

● @Module():模块装饰器,用于在Nest中划分功能模块并限制依赖注入的范围。

● @UseInterceptors():用于绑定拦截器,将拦截器的作用范围限制在控制器类范围中(当然也可以作用在类方法上)。

● @Get、@Post:用于定义路由方法的HTTP请求方式。

● @IsNotEmpty、@IsString、@IsNumber:用于在参数的验证场景中校验HTTP请求的参数是否符合预期。

● @Body、@Param、@Query:用于接收HTTP请求发送的数据,不同的请求方式对应不同的参数接收方式。

Nest中的装饰器主要分为这几类。理解了它们将有助于我们在使用过程中更加得心应手。关于这些装饰器的具体使用方法,我们将在后续章节中逐一进行详细介绍。 y4aZxW4RX9lioUv+VQfnRDUfXUJ98yXf16F1MlqBOFz4pfsUHOG3wlFUw1JtJpD7

点击中间区域
呼出菜单
上一章
目录
下一章
×