美文网首页
TypeScript: 类的装饰器(一)

TypeScript: 类的装饰器(一)

作者: Rollover | 来源:发表于2020-02-23 21:09 被阅读0次

    假设我有一个汽车工厂,每天都在生产汽车,他们都有统一的名字和价格,都可以在公路上开,那么,我们很容易写出如下代码:

    PS: 如果没有搭建 TypeScript 的开发环境,请看这里

    class Car {
      private name: string;
      private price: number;
    
      constructor(name: string, price: number) {
        this.name = name;
        this.price = price;
      }
    
      getName() {
        console.log(this.name);
      }
    
      getPrice() {
        console.log(this.price);
      }
    
      drive() {
        console.log("drive");
      }
    }
    
    const toyota: Car = new Car("toyota", 175000);
    toyota.getName();
    toyota.getPrice();
    toyota.drive();
    

    那么,当我需要为每一辆出厂的车都安装行车记录仪器时,那么,我们可能会修改为如下代码:

    class Car {
      private name: string;
      private price: number;
    
      constructor(name: string, price: number) {
        this.name = name;
        this.price = price;
      }
    
      getName() {
        console.log(this.name);
      }
    
      getPrice() {
        console.log(this.price);
      }
    
      drive() {
        console.log("drive");
      }
      // 添加行车记录仪
      driveRecorder() {
        console.log("driveRecorder");
      }
    }
    
    const toyota: Car = new Car("toyota", 175000);
    toyota.getName();
    toyota.getPrice();
    toyota.drive();
    toyota.driveRecorder();
    

    上面代码能正确执行,我们也为每辆出厂的车添加上了行车记录仪。那么,现实中行车记录仪一般都是,客户买了车后才会去安装的,也就是说,车辆在设计的时候不会考虑把一些非必要的配件都设计上,只会留出空间,让客户去安装。同理,从代码的角度 driveRecorder 这个方法不应改写进 Car 类里边,它不是在类本身的东西,是之后加上的,上面的代码显然破坏了类的设计,那么我们可以把 driveRecorder 添加到类的外面,也就是把它做成一个装饰器,装饰我们的类,那么我们的代码修改为如下:

    function recorder(constructor: any) {
      constructor.prototype.driveRecorder = () => {
        console.log("driveRecorder");
      };
    }
    
    @recorder // @recorder 为类的装饰器
    class Car {
      private name: string;
      private price: number;
    
      constructor(name: string, price: number) {
        this.name = name;
        this.price = price;
      }
    
      getName() {
        console.log(this.name);
      }
    
      getPrice() {
        console.log(this.price);
      }
    
      drive() {
        console.log("drive");
      }
    }
    
    const toyota: Car = new Car("toyota", 175000);
    toyota.getName();
    toyota.getPrice();
    toyota.drive();
    toyota.driveRecorder();
    

    那么,如果您直接抄上面的代码,可能会得到如下两个报错提示:

    1.装饰器语法报错

    通过提示我们知道,TypeScript的装饰器在ES语法中属于一个实验性值的语法,故在VSCode中会报错,如果要使用装饰器
    则需要把tsconfig.json的'experimentalDecorators'的注释打开才能解除警报,如下图


    2.实例调用装饰器方法报错

    关于这个错误,我们看下装饰器

    function recorder(constructor: any) {
      constructor.prototype.driveRecorder = () => {
        console.log("driveRecorder");
      };
    }
    

    在 TypeScript 的类装饰器中,装饰器是一个函数,那么它的参数就是这个类,这里的 constructor 就是我们传入的 Car 类,我们用原型的方法把 driveRecorder 挂载到 constructor 而 constructor 的类型声明为 any,toyota 的类型为 Car,两个类型不一样,所以找不该 driveRecorder 方法报错,这里我们就临时改一下调用的方式(把 toyota 的类型临时改成any):

    (toyota as any).driveRecorder();
    

    那么报错没了,我们运行下代码,结果是对的

    回过头来看装饰器和原来在类中的修改,执行的结果是一样的,但编程的思想却不一样,直接在类中修改看似很方便,也是我们最容易想到的一个方式,但这只是我们在最舒适的环境下想到的,有可能,这个类不是我们写,是别人写的,那么非常不推荐大家去修改别人的代码,这里推荐使用装饰器,直接在别人写好的类上面加上,不会破坏别人的代码
    原文链接

    相关文章

      网友评论

          本文标题:TypeScript: 类的装饰器(一)

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