typescript-装饰器(十三)

装饰器

概括

  • 装饰器是一种特殊类型的声明,它能被附加到类、方法、访问器、属性、或参数上,用@添加
  • 目前TS中依旧为一个测试中的版本,若要启用实验性的装饰器特性,需要在命令行或tsconfig.json里面启用experimentalDecorators编译器选项

类的装饰器

  • 类装饰器就是在类声明之前被声明
  • 类装饰器被应用于类的构造函数,可以用来观察修改替换类定义
  • 类装饰器不能用来声明文件中(.d.ts),也不能用在任何外部上下文中(比如declare的类)
  • 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数
  • 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明

类装饰器的基本认识

function testDecorator(constructor: any){
  constructor.prototype.uname = "法外狂徒张三"
  constructor.prototype.show = ():void =>{
    console.log("类装饰器")
  }
}
@testDecorator
class Person{
}
let person = new Person();
// 需要使用断言,才能调到show方法
(person as any).show()

类装饰器添加参数

// 工厂函数
function testDecorator(flag: boolean){
  if(flag){
    return function (constructor: any) {
      constructor.prototype.uname = "法外狂徒张三"
      constructor.prototype.show = ():void =>{
        console.log("类装饰器")
      }
    }
  }else{
    return function (constructor: any){
      constructor.prototype.show = ():void => {
        console.log(`我的名字叫${constructor.prototype.uname}`)
      }
    }
  }
}

@testDecorator(true)
class Person{
}
let person = new Person();
// 需要断言,才能调到show方法
(person as any).show()

类装饰器中利用泛型

/** 
 * @param constructor 
 *  T 就相当于一个类
 *  函数可以接受很多的参数,参数类型都是为any类型,最好把这些都放在了数组中
 */
function testDecorator<T extends new(...args: any[]) => {}>(constructor: any){
  return class extends constructor{
    name = "法外狂徒张三"
    age = 18
    show() {
      console.log(this.name)
    }
  }

}

@testDecorator
class Person{
  name: string
  constructor(uname: string){
    this.name = uname
  }
}
let person = new Person('富甲一方赵六')
console.log(person); // Person {name: '法外狂徒张三',age: 18}
// 需要断言  才能调show方法
(person as any).show()  // 法外狂徒张三

类装饰器的使用

/** 
 * @param constructor 
 *  T 就相当于一个类
 *  函数可以接受很多的参数,参数类型都是为any类型,最好把这些都放在了数组中
 */
function testDecorator() {
  return function <T extends new(...args: any[]) => {}>(constructor: T){
    return class extends constructor{
      name = "法外狂徒张三"
      age = 18
      show() {
        console.log(this.name)
      }
    } 
  }
}
 

const Person = testDecorator()(
  class {
    name: string
    constructor(uname: string){
      this.name = uname
    }
  }
)
let person = new Person('富甲一方赵六')
console.log(person); // Person {name: '法外狂徒张三',age: 18}
// (person as any).show()  // 法外狂徒张三
person.show()

方法装饰器

方法装饰器的概述

  • 方法装饰器写在一个方法的声明之前
  • 方法装饰器可以用来监视修改替换方法
  • 方法装饰器表达式会在运行时,当作函数被调用,传入下列三个参数
    • 静态成员的类的构造函数实例成员的类的原型
    • 成员的名称
    • 该成员的属性描述符
/**
 * @param target
 *  普通方法:target对应的就是prototype
 *  静态方法:target对应的就是类的构造函数
 * @param key
 * @param desciptor
 *  desciptor.writable = false // 不允许对方法进行修改
 *  desciptor.value = function() { } //输出指定的内容
 */
function getNameDecorator(target: any,key: string,desciptor: PropertyDescriptor){
  desciptor.value = function (){
    return "desciptor"
  }

}
class Test{
  name: string = "法外狂徒张三"
  constructor(uname: string){
    this.name = uname
  }
  @getNameDecorator
  getName(){
    return this.name
  }
  // @getNameDecorator
  static show(): void{
    console.log(`他的描述${this.name}`)
  }
}
let test = new Test('张三')
console.log(test.getName()) // desciptor

访问器的装饰器

访问器的装饰器概述

  • 访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)
  • 访问器装饰器应用于访问器的属性描述并且可以用来监视修改替换一个访问器的定义
  • 访问器装饰器不能用在声明文件(.d.ts)或任何外部上下文(比如declare的类)里
  • 访问器装饰器表达式会在运行时当作函数被调用,传入3个参数:
    • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    • 成员的名字
    • 描述对象
  • ts不允许同时装饰一个成员的get 和set访问器
function visitDecorator(target: any,key: string,desciptor: PropertyDescriptor){

  // 禁止通过访问器set修改参数的属性值
  desciptor.writable = false
}

class Test{
  private _name: string
  constructor(uname: string){
    this._name = uname
  }

  @visitDecorator
  get name(){
    return this._name
  }

  set name(userName: string){
    this._name = userName
  }
}

const test = new Test('法外狂徒张三')
// console.log(test.name) // 法外狂徒张三
// test.name = '富甲一方钱七' // 报错
// console.log(test.name) // 富甲一方钱七

属性的装饰器

属性装饰器的概述

  • 属性的装饰器声明在一个属性的声明之前(紧靠着访问器声明)
  • 属性的装饰器应用于属性描述并且可以用来监视修改替换一个访问器的定义
  • 属性的饰器不能用在声明文件(.d.ts)或任何外部上下文(比如declare的类)里
  • 属性的装饰器表达式会在运行时当作函数被调用,传入2个参数:
    • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    • 成员的名字

属性装饰器的基本使用

function nameDecorator(target: any,key: string){

}


class Test{
  @nameDecorator
  name: string = "法外狂徒张三"
}

let test = new Test()
console.log(test.name) // 法外狂徒张三

属性装饰器的进阶使用

function nameDecorator(target: any,key: string): any{
  // 属性不可修改
  const desciptor: PropertyDescriptor = {
    writable: false
  }
  return desciptor
  // 修改的并不是实例上的name,而是原型上的name
  target[key] = "权倾朝野王五"
}


class Test{
  @nameDecorator
  // name是放在实例上面的
  name: string = "法外狂徒张三"
}

let test = new Test()
console.log(test.name) // 法外狂徒张三
// test.name = "富甲一方钱七" // error,readonly属性
console.log((test as any)._proto_.name) // 权倾朝野王五

参数装饰器

参数装饰器的概述

  • 参数装饰器声明在一个参数声明之前(紧靠着访问器声明)
  • 参数装饰器用于类构造函数或方法声明
  • 参数装饰器不能用在声明文件(.d.ts),重载或任何外部上下文(比如declare的类)里
  • 参数装饰器表达式会在运行时当作函数被调用,传入3个参数:
    • 对于静态成员来说是当前类,对于实例成员是当前实例
    • 参数所在的方法名称
    • 参数在参数列表中的索引
function paramDecorator(target: any,key: string,index: number){

}
class Test{
  getInfo(@paramDecorator name: string,age: number){
    console.log(name,age)
  }
}

let test = new Test()
test.getInfo("法外狂徒张三",20)

案例

方法装饰器—问题

function catchErrorDecorator(target: any,key: string,desciptor: PropertyDescriptor){
  const fn = desciptor.value
  desciptor.value = function(){
    try{
      fn()
    }catch (e){
      console.log("userInfo上不存在该属性")
    }
  }
}

const userInfo: any = undefined

class Test{
  @catchErrorDecorator
  getName(){
    return userInfo.name
  }
  @catchErrorDecorator
  getAge(){
    return userInfo.age
  }
}
const test = new Test()
test.getName() // userInfo上面不存在该属性
test.getAge() // userInfo上面不存在该属性

方法装饰器—工厂模式解决wenti

// 工厂模式
function catchErrorDecorator(msg: string){
  return function(target: any,key: string,desciptor: PropertyDescriptor) {
    const fn = desciptor.value
    desciptor.value = () =>{
      try{
        fn()
      }catch (e){
      console.log(msg)
      }
    }
  } 
}

const userInfo: any = undefined

class Test{
  @catchErrorDecorator("userInfo.name 不存在")
  getName(){
    return userInfo.name
  }
  @catchErrorDecorator("userInfo.age 不存在")
  getAge(){
    return userInfo.age
  }
}
const test = new Test()
test.getName() // userInfo.name 不存在
test.getAge() // userInfo.age 不存在
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值