类的装饰器

作者: 泡杯感冒灵 | 来源:发表于2022-04-15 12:26 被阅读0次
    装饰器本身是一个函数,因为装饰器是对类进行修饰的,所以是类的装饰器,装饰器通过@符号来使用。
    装饰器接受的参数是一个类的构造函数
    function testDecorator (constructor: any) {
          constructor.prototype.getName = () => {
            console.log('weiyang');
          };
    }
    @testDecorator(true)
    class Test{ }
    (test as any).getName()
    
    装饰器的运行时机是类创建好后,立即执行,而不是实例化一个类的时候。
    可以有多个装饰器,装饰器执行顺序是从下到上,从右到左。
    function testDecorator1 (constructor: any) {
          constructor.prototype.getName = () => {
            console.log('yang1');
          };
    }
    function testDecorator2 (constructor: any) {
          constructor.prototype.getName = () => {
            console.log('yang2');
          };
    }
    
    @testDecorator1  @testDecorator2 class Test{ }
    
    对装饰器做工厂模式的包装,就可以做一些参数上的判断了
    function testDecorator(flag: boolean) {
      if (flag) {
        return function (constructor: any) {
          constructor.prototype.getName = () => {
            console.log('weiyang');
          };
        }
      } else {
        return function (constructor: any) {}
      }
    }
    
    
    @testDecorator(true)
    class Test{ }
    
    const test = new Test();
    (test as any).getName()
    
    上边装饰器的写法,我们通过test .getName()的时候,不会主动提示。所以不是一种特别正规的装饰器的写法。正规的怎么写呢?
    function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
      // 这里改造的构造函数后执行
      return class extends constructor{
        name = 'lee';
        getName() {
          return this.name;
        }
      }
    }
    
    
    @testDecorator
    class Test{
      name: string;
      // 这个构造函数先执行
      constructor(name: string) {
        this.name = name;
      }
    }
    
    const test = new Test('yang');
    console.log((test as any).getName());  // 没有改造构造函数之前返回 {name:'yang'},改造之后返回 {name:'lee'}
    
    • <T extends new (...args:any[]) => any>解析一下这个泛型,泛型T继承了自一个构造函数,这个构造函数,接受任意类型的数据组成的数组作为参数,这个构造函数返回任意类型的数据
    • class extends constructor{}这里是对构造函数进行改写。这个改写的执行是在定义类的构造函数之后执行的。
    • (constructor: T) 这里的意思是 constructor的类型就是一个泛型,这个泛型 T的意思是,可以通过实例化创建出一个类,这个类应该包含new (...args:any[]) => any这样的构造函数
    经过上边的写法后,我们去通过test调用getName方法还是会报错,除非是 test as any才可以。原因是 我们定义类test的时候,并没有直接定义getName方法,而getName是testDecorator装饰器偷偷的装饰的时候加进来的,这个时候typescript是不知道加了这个方法的,要解决这个问题,需要工厂模式
    function testDecoratorFactory() {
      return function <T extends new (...args: any[]) => any>(constructor: T) {
        // 这里改造的构造函数后执行
        return class extends constructor{
          name = 'lee';
          getName() {
            return this.name;
          }
        }
      }
    }
    
    
    // 这个时候testDecoratorFactory不是当成一个装饰器来用,而是当成一个函数来用
    // testDecoratorFactory()函数执行,返回一个装饰器
    // 装饰器后边再跟(class {}),表示装饰器装饰的是一个没用名字的class,这个class就多出一个getName的方法了
    // 修饰完成之后,把返回的东西复制给 Test
    const Test = testDecoratorFactory()(class {
      name: string;
      constructor(name: string) {
        this.name = name;
      }
    })
    
    // 这里再去new 的Test是装饰器装饰过后的 class
    // 所以实例 test就可以访问到getName了
    const test = new Test('yang');
    console.log(test.getName());
    

    相关文章

      网友评论

        本文标题:类的装饰器

        本文链接:https://www.haomeiwen.com/subject/jyjtertx.html