目录
前言
本文收录于TypeScript知识总结系列文章,欢迎指正!
程序遵循开放封闭原则,即在设计和编写软件时应该尽量避免对原有代码进行修改,而是通过添加新的代码来扩展软件的功能。
在日常开发中不知你有没有遇到以下情况,我们封装了一个Request模块,现在需要对请求进行拦截,访问请求参数,此时我们可以通过装饰器针对请求函数或者请求类进行访问,获取参数并解析
定义
在TS中,装饰器是一种特殊类型的声明。可以附加到类、方法、属性或参数上用于修改类的行为或属性。
在面向对象编程中,有时需要对类的行为和功能做出修改,直接修改类的内部可能会使成本升高,或出现其他问题;此时可以使用装饰器来修改类,在保证类内部结构与功能不变的前提下对数据或行为进行迭代
TS中装饰器可以分为类装饰器、方法装饰器、属性装饰器和参数装饰器。
tips:使用装饰器前需要在tsconfig中开启experimentalDecorators属性
类装饰器
类装饰器是应用于类的构造函数的函数,它可以用来修改类的行为。类装饰器可以有一个参数,即类的构造函数,通过这个参数我们可以对类的行为进行修改。
基本用法
类装饰器的语法是在一个普通的函数名前面加上@符号,后面紧跟着要装饰的类的声明,如:
const nameDecorator = (constructor: typeof Animal) => {
console.log(constructor.prototype.name)// undefined
}
@nameDecorator
class Animal {
name: string = "阿黄"
constructor() {
console.log(this.name);// 阿黄
}
}
new Animal()
在上述代码中,我使用decorator获取Animal类的name属性,发现获取的是未定义,而在构造函数中却可以获取,原因是类的装饰器是在类定义时对类进行操作的,而属性及函数的初始化是当类实例化时进行的,所以获取不到name的值
操作方式
通过类装饰器操作类的方式有两种:操作类的原型和类的继承
操作类的原型
ES6之前的类是通过构造函数实现的,其原型prototype属性是存在的,所以我们在对类进行操作时可以使用修改原型的方式
type IAnimal = {
name?: string
getName?: () => string
}
const nameDecorator = (constructor: Function) => {
const _this = constructor.prototype // 模拟类内部环境
_this.name = "阿黄"
_this.getName = () => {
return _this.name
}
}
@nameDecorator
class Animal implements IAnimal { }
const animal: IAnimal = new Animal()
console.log(animal.getName()) // 阿黄
上面代码实现了对类中name属性初始化以及实现了类的getName方法,在ES5中如何实现类的重写?看看下面代码对装饰器的修改:
const nameDecorator = (constructor: IAnimalProto) => {
const _this = constructor.prototype // 模拟类内部环境
_this.name = "阿黄"
return class extends constructor {
getName = () => {
return "名字:" + _this.name
}
}
}
tips:如果通过这种方式无法修改类的属性或方法,可以把tsconfig中target属性调整为ES5,兼容低版本浏览器,此时类是通过构造函数实现的
类继承操作
ES6中的类语法糖中没有prototype属性,所以我们可以使用继承的方式实现上面的代码,并使用重写的方式修改类中的同名函数
type IAnimal = {
name?: string
getName?: () => string
}
type IAnimalProto = {
new(): Animal
} & IAnimal
const nameDecorator = (constructor: IAnimalProto) => {
return class extends constructor {
constructor(public name = "阿黄") {
super()
}
getName() {// 重写类中的函数
return "姓名:" + this.name
}
}
}
@nameDecorator
class Animal implements IAnimal {
name?: string;
getName() {
return this.name
}
}
const animal: IAnimal = new Animal()
console.log(animal.getName()) // 姓名:阿黄