装饰器

目前 js 支持装饰器。但还未进入标准。是一种面向对象的编程方式

解决什么问题

  1. 分离关注点。例如:对用户对象中的数据进行验证
  2. 重复代码问题
  3. 能够带来额外的信息量,看可以为某些属性、类、参数、方法提供元数据信息。这样在运行时我们可以拿到这些元数据进行我们想要的操作

上述前两个问题产生的根源:某些信息,在定义时,能够附加的信息量有限

装饰器的本质

在 js 中,装饰器是一个函数,因为是 js 的东西,所以会参与运行

类装饰器

类装饰器本质是一个函数,该函数接受一个参数,表示类本省(构造函数本省)。

  • 因为装饰器还不是标准,在 ts 中使用时会报错,需要开启 experimentalDecorators
  • 装饰器函数的运行时间:在类定义后直接运行
  • 类装饰器的返回值只有两种:void(仅运行函数)、返回一个新的类(会将新的类替换掉装饰目标)
//在 ts 中,该函数必须接收一个参数,代表装饰的类,且需要约束构造函数函数的参数
function test(target: new(...args: any[]) => object){ 
}
@test
class A {
	constructor(public a:string){}
}

// 给装饰器传参
// 执行装饰器,并且返回值需要是一个装饰器
function test(a:string) {
	return function (target: new(...args: any[]) => object){ 
	}
}
@test('fdsfds')
class A {
	constructor(public a:string){}
}

// 多个装饰器的情况
// 装饰器从下往上执行
// 如果是给装饰器传参的情况,那么先执行函数,然后返回的装饰器才按照从下往上的顺序执行
type constructor = new (...args:any[]) => object
function d1(target:constructor){}
function d2(target:constructor){}
// function d1(){ return funciton (target:constructor){} }
// function d2(){ return funciton (target:constructor){} }
@d2
@d1
// @d2() 先执行 d2 然后返回装饰器
// @d1() 先执行 d1 然后返回装饰器
// 返回的装饰器在类定义完后,按照从下往上也就是 d1、d2 的顺序执行
class A {}

成员装饰器

属性装饰器

属性装饰器也是一个函数,该函数接收两个参数

  • 第一个参数:如果是静态属性,则为类本身;如果是实例,则为类的原型
  • 第二个参数:固定位一个字符串,表示属性名
function d(target:any, key:string){}
class A {
	@d
	prop1:string

	@d
	static prop2:string
}

方法装饰器

方法装饰器也是一个函数,该函数接收三个参数

  • 第一个参数:如果是静态方法,则为类本身;如果是实例方法,则为类的原型
  • 第二个参数:固定为一个字符串,表示方法名
  • 第三个参数:描述符对象(可以用 Object.defineProperty 定义的那个描述符)
function m() {
	return functioin (target: any, key: string, descriptor: PropertyDescriptor){}
}
class A {
	@m()
	method1() {}
}

装饰器补充

常用库

  • reflect-metadata
    • 由于我们在使用装饰器时,需要存储一些元信息,通常我们可以挂载在原型上,但是这样会造成原型污染。所以我们应该将其存储在外部。reflect-metadata 就为我们提供了这样的外部元信息存储的能力 (类、属性等的元数据存储)。
  • class-validator
    • 用来做数据校验,提供了各种校验装饰器,例如 @Length、@Max 等。ts 在运行时没有类型检查,我们可以借助该库,做一些运行时的校验
  • class-transformer
    • 用来把平面对象转换为指定的类的实例对象。通常用于在服务端做类型校验,将接受到的数据进行转换为对象,然后结合 class-validator 对数据进行校验。例如:
// 服务端定义的 User 类型
class User {
	name: string
	age: number
	height: number
}

// 前端发送过来的数据
ctx.request.body = {
	name: 'fdsfd',
	age: '123',
	height: 178
}

const user = plainToClass(ctx.request.body, User)

参数装饰器:依赖注入、依赖倒置(用到很少,大型后端项目)
要求有三个参数:

  • 第一个参数:如果方法是静态的,则为类本省,如果方法是实例方法,则为类的原型
  • 参数名称
  • 在参数列表中的索引
function test(target: any, method: string, index:number){}
class A {
	sum(a: number, @test b:number){}
}

关于 TS 自动注入元数据:如果安装了 reflect-metadata ,并且导入了该库,并且在某个成员上添加了元数据,并且启用了 emitDecoratorMetadata,则在 TS 编译结果中,会将类型约束,作为元数据加入到相应位置,这样一来,TS 的类型检查将有机会在运行时进行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值