装饰器定义

  • 装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为
  • 常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器
  • 装饰器的写法分为普通装饰器和装饰器工厂

    类装饰器

  • 类装饰器在类声明之前声明,用来监控、修改或替换类定义

  • 参数是类的定义或者构造函数

代码示例

基本的装饰器

  1. export {};
  2. // 类的装饰器,参数target是类的构造函数本身
  3. interface Animal {
  4. swings: number;
  5. fly: () => {};
  6. }
  7. function flyable(target: any) {
  8. console.log(target);
  9. target.prototype.swings = 2;
  10. target.prototype.fly = function () {
  11. console.log("我能飞");
  12. };
  13. }
  14. @flyable
  15. class Animal {
  16. constructor() {}
  17. }
  18. let animal: Animal = new Animal();
  19. console.log(animal.swings);
  20. animal.fly();

类的装饰器工厂

  1. // 类的装饰器工厂,可以传递不同参数值,参数target是类的构造函数本身
  2. interface Animal {
  3. swings: number;
  4. fly: () => {};
  5. }
  6. function flyable(swings: number) {
  7. return function flyable(target: any) {
  8. console.log(target);
  9. target.prototype.swings = swings;
  10. target.prototype.fly = function () {
  11. console.log("我能飞");
  12. };
  13. };
  14. }
  15. @flyable(4)
  16. class Animal {
  17. constructor() {}
  18. }
  19. let animal: Animal = new Animal();
  20. console.log(animal.swings);
  21. animal.fly();

多种类型的装饰器方法

  1. // 实例属性的装饰器,target是类原型对象,key是属性的名字
  2. function instancePropertyDecorator(target, key) {
  3. target.protoName = "这是类实例上的属性";
  4. console.log("instancePropertyDecorator", target, key);
  5. }
  6. // 类的静态属性,target是类的构造函数,key是属性名
  7. function classPropertyDecorator(target, key) {
  8. console.log("classPropertyDecorator", target, key);
  9. }
  10. // 实例方法,target是类的原型,key是方法名,descriptor属性描述符
  11. function instanceMethodDecorator(target, key, descriptor) {
  12. console.log("instanceMethodDecorator", target, key, descriptor);
  13. }
  14. function classMethodDecorator(target, key, descriptor) {
  15. console.log("classMethodDecorator", target, key, descriptor);
  16. }
  17. interface Person {
  18. instanceProperty: string;
  19. protoName: string;
  20. }
  21. class Person {
  22. // 实例的属性装饰器
  23. // 实例的属性装饰器
  24. @instancePropertyDecorator
  25. instanceProperty!: string; //实例属性
  26. //实例属性
  27. // 类的属性装饰器
  28. @classPropertyDecorator
  29. static classProperty: string; //类的静态属性
  30. // 实例的方法装饰器
  31. @instanceMethodDecorator
  32. instanceMethod() {
  33. //实例的方法
  34. }
  35. // 类的方法装饰器
  36. @classMethodDecorator
  37. classMethod() {}
  38. }
  39. let p = new Person();
  40. console.log(Person.prototype.protoName);
  41. console.log(p.protoName);

数据埋点的运用

  1. function before(beforeFn) {
  2. return function (target, methodName, descriptor) {
  3. let oldMethod = descriptor.value;
  4. descriptor.value = function () {
  5. beforeFn.apply(this, arguments);
  6. return oldMethod.apply(this, arguments);
  7. };
  8. };
  9. }
  10. function after(afterFn) {
  11. return function (target, methodName, descriptor) {
  12. let oldMethod = descriptor.value;
  13. descriptor.value = function () {
  14. let result = oldMethod.apply(this, arguments);
  15. afterFn.apply(this, arguments);
  16. return result;
  17. };
  18. };
  19. }
  20. class App extends Component {
  21. @before(() => console.log("before"))
  22. onClickBefore() {
  23. console.log("beforeClick");
  24. }
  25. @after(() => console.log("after"))
  26. onClickAfter() {
  27. console.log("afterClick");
  28. }
  29. @after(() => fetch("/api/json"))
  30. ajaxClick() {
  31. console.log("ajax data");
  32. }
  33. render() {
  34. return (
  35. <div>
  36. <button onClick={this.onClickBefore}> beforeClick</button>
  37. <button onClick={this.onClickAfter}>afterClick</button>
  38. </div>
  39. );
  40. }
  41. }

表单数据校验的运用

  1. // 表单校验
  2. Function.prototype.before = function (beforeFn) {
  3. let thisFn = this;
  4. return function () {
  5. let pass = beforeFn();
  6. if (pass) {
  7. thisFn.apply(this, arguments);
  8. }
  9. };
  10. };
  11. function registerFn(event) {
  12. console.log("提交表单");
  13. }
  14. registerFn = registerFn.before(function () {
  15. let username = document.getElementById("username").nodeValue;
  16. if (!username) {
  17. return alert("用户名有无");
  18. }
  19. return true;
  20. });