• 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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    类装饰器添加参数

    // 工厂函数
    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    类装饰器中利用泛型

    /** 
     * @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()  // 法外狂徒张三
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    类装饰器的使用

    /** 
     * @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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    方法装饰器

    方法装饰器的概述

    • 方法装饰器写在一个方法的声明之前
    • 方法装饰器可以用来监视修改替换方法
    • 方法装饰器表达式会在运行时,当作函数被调用,传入下列三个参数
      • 静态成员的类的构造函数实例成员的类的原型
      • 成员的名称
      • 该成员的属性描述符
    /**
     * @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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    访问器的装饰器

    访问器的装饰器概述

    • 访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)
    • 访问器装饰器应用于访问器的属性描述并且可以用来监视修改替换一个访问器的定义
    • 访问器装饰器不能用在声明文件(.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) // 富甲一方钱七
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    属性的装饰器

    属性装饰器的概述

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

    属性装饰器的基本使用

    function nameDecorator(target: any,key: string){
    
    }
    
    
    class Test{
      @nameDecorator
      name: string = "法外狂徒张三"
    }
    
    let test = new Test()
    console.log(test.name) // 法外狂徒张三
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    属性装饰器的进阶使用

    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) // 权倾朝野王五
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    参数装饰器

    参数装饰器的概述

    • 参数装饰器声明在一个参数声明之前(紧靠着访问器声明)
    • 参数装饰器用于类构造函数或方法声明
    • 参数装饰器不能用在声明文件(.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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    案例

    方法装饰器—问题

    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上面不存在该属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    方法装饰器—工厂模式解决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 不存在
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    楼宇天台视频AI智能监管方案,时刻保障居民安全
    神经网络入门
    高并发笔记
    设计模式:命令模式
    MybatisPlus——全网配置最全的代码生成器
    新版Java面试专题视频教程——框架篇
    Vue脚手架的搭建
    nginx 安装编译并指定安装目录
    Javascript中常用方法
    蓝桥杯拿到一等奖,并分享经验
  • 原文地址:https://blog.csdn.net/qq_39656068/article/details/126038667