# 类的装饰器
# 概念
首先装饰器本身是一个函数,修饰类的装饰器,接收的参数是一个构造函数;
需要注意的是我们使用装饰器是不能直接使用的,,需要打开 tsconfig.json 的一个配置 "experimentalDecorators": true 与 "emitDecoratorMetadata": true
function testDecorator(constructor: any) {
constructor.prototype.getName = () => {
console.log(111)
}
console.log(111)
}
// 装饰器通过 @ 符号来使用
// 装饰器执行的顺序是从下到上,从右到左的顺序
@testDecorator
class Test {}
注意,装饰器通过 @ 符号来使用,多个装饰器执行的顺序是从下到上,从右到左的顺序;
装饰器函数也可以在里面做判断:
// 类的装饰器
// 装饰器本身是一个函数
function testDecorator(flag: boolean) {
if (flag) {
// 修饰类的装饰器,接收的参数是一个构造函数
return function (constructor: any) {
constructor.prototype.getName = () => {
console.log(111)
}
console.log(111)
}
}
return function (constructor: any) {}
}
// 装饰器通过 @ 符号来使用
// 装饰器执行的顺序是从下到上,从右到左的顺序
@testDecorator(true)
class Test {}
const descTesart = new Test()(descTesart as any).getName()
通过装饰器扩展修改属性:
function testDecorator<T extends new (...args: any[]) => any> (constructor: T) {
return class extends constructor {
name = 'cj'
}
}
@testDecorator
class Test {
name: string
constructor(name: string) {
this.name = name
}
}
const descTesart = new Test('jie')
console.log(descTesart.name)
类装饰方法。 上面的代码在调用 getName 方法的时候,会报错,需要使用 (descTesart as any).getName() 这种方式来调用,我们可以修改代码,来解决这个问题:
function testDecorator() {
return function <T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
getName() {
return this.name
}
}
}
}
const Test = testDecorator()(
class {
name: string
constructor(name: string) {
this.name = name
}
}
)
const descTesart = new Test('jie')
console.log(descTesart.getName())
# 类中方法的装饰器
// 普通方法,target 对应的是类的 prototype
// 静态方法 target 对应的是类的构造函数
// key 装饰的方法的名字
// descriptor 类似属性描述符
function getNameDecorator(
target: any,
key: string,
descriptor: PropertyDescriptor
) {
// 方法不可以被重写
descriptor.writable = false
// 修改方法
descriptor.value = function () {
return 'decorator'
}
}
class Test {
name: string
constructor(name: string) {
this.name = name
}
@getNameDecorator
getName() {
return this.name
}
}
const test = new Test('jie')
console.log(test.getName())
# 类中访问器的装饰器
// 同方法的访问器参数
function visitDecorator(
target: any,
key: string,
descriptor: PropertyDescriptor
) {
// 不可修改
// descriptor.writable = false
descriptor.value = '3333'
}
class Test {
private _name: string
constructor(name: string) {
this._name = name
}
get name() {
return this._name
}
@visitDecorator
set name(name: string) {
this._name = name
}
}
const test = new Test('jie')
test.name = '123'
console.log(test.name)
# 属性的装饰器
属性的装饰器与类的跟方法的装饰器是不一样的,接收的参数是没有修饰符对象的。
// target 原型
// key 属性名字
function nameDecorator(target: any, key: string) {
console.log(target, key) // Test{} name
}
class Test {
@nameDecorator
name: 'jie'
}
const test = new Test()
console.log(test.name)
如果我们需要设置属性不能修改,需要我们进行自定义装饰符对象:
function nameDecorator(target: any, key: string): any {
const descriptor: PropertyDescriptor = {
writable: false,
}
return descriptor
}
class Test {
@nameDecorator
name: 'jie'
}
const test = new Test()
console.log(test.name)
如果我们需要修改属性值:
// 修改的并不是实例上的 name,而是原型上的 name
function nameDecorator(target: any, key: string): any {
// 这样直接修改数值是不行的--这里修改的是 prototype 上面的 name
target[key] = 'giser'
}
class Test {
@nameDecorator
name: 'jie'
}
const test = new Test()
// test.name = 'giser' // 在这里进行修改
console.log(test.name)
# 参数装饰器
也就是对类中方法的参数进行装饰;他跟前面的装饰器接收的参数都是不一样的:
// 原型、方法名、参数所在的位置
function paramDecorator(target: any, key: string, paramIndex: number): any {
console.log(target, key, paramIndex)
}
class Test {
getInfo(@paramDecorator name: string, age: number) {
console.log(name, age)
}
}
const test = new Test()
test.getInfo('jie', 18)
# 装饰器实际使用的小例子
比如我们有如下代码,我们访问一个 any 类型的对象,在类中访问他的属性,会报错,我们可以添加 try catch 来防止报错, 但是如果这样的话,需要添加很多 try catch;
const userInfo: any = undefined
class Test {
getName() {
try {
return userInfo.name
} catch (e) {
console.log('userInfo.name 不存在')
}
}
getAge() {
try {
return userInfo.age
} catch (e) {
console.log('userInfo.age 不存在')
}
}
}
const test = new Test()
test.getName()
我们可以通过方法装饰器来解决这个问题:
const userInfo: any = undefined
function catchError(msg: string) {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const fn = descriptor.value
descriptor.value = function () {
try {
fn()
} catch (e) {
console.log(`${msg} 不存在`)
}
}
}
}
class Test {
@catchError('userInfo.name')
getName() {
return userInfo.name
}
@catchError('userInfo.age')
getAge() {
return userInfo.age
}
}
const test = new Test()
test.getName()
阅读量: