js css html

类的装饰器

2022-04-15  本文已影响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'}
经过上边的写法后,我们去通过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());
上一篇下一篇

猜你喜欢

热点阅读