• 08、TypeScript 装饰器


    1.类装饰器

    /*
      装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为
      通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能
      常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
      装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可以传参)
      装饰器是过去几年中 js 最大的成就之一,也是 es7 的标准特性之一
    */
    // 类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。
    // 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数
    
    // 定义一个装饰器(普通装饰器)
    function logClass(params: any) {
      // params 就是指当前类
      console.log(params);
      // 给这个类扩展一个属性 url
      params.prototype.url = '动态扩展的属性';
    }
    
    // 声明一个类
    // 使用装饰器(普通装饰器),可以扩展类的属性和方法,在不修改类的前提下,扩展类的功能
    @logClass
    class HttpClient {
      name: string;
    
      constructor(name: string) {
        this.name = name;
      }
    
      getData(): void {
    
      }
    }
    
    // 实例化,这里加上 any ,h.url 就不会报错了
    var h: any = new HttpClient('zhangning');
    console.log(h.url);
    
    // 类装饰器工厂(可以传参)
    function logClass1(params: string) {// params 表示传递的参数
      return function(target: any) {// 这里的参数 target 指的是当前的类
        console.log(params);// hellow
        console.log(target);// HttpClient(){}
        target.prototype.url = params;
      };
    }
    
    @logClass1('hellow')
    class HttpClient1 {
      constructor() {
      }
    
      getData() {
    
      }
    }
    
    let h1: any = new HttpClient1();
    console.log(h1.url);

      重载构造函数例子

    // 重载构造函数的例子,
    // 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
    // 如果类装饰器返回一个值,他会使用提供的构造函数来替换类的声明
    
    // 定义装饰器,在装饰器中修改构造函数(就是重载构造函数)
    function logClass11(target: any) {
      console.log(target);
      return class extends target {
        url: any = '我是装饰器中修改的数据';
        getData(){
          console.log(this.url)
        }
      };
    }
    
    //
    @logClass11
    class HttpClient11 {
      url: string | undefined;
    
      constructor() {
        this.url = '我是构造函数中的url';
      }
    
      getData(): void {
        console.log(this.url);
      }
    }
    
    let h11 = new HttpClient11();
    h11.getData();// 我是构造函数中的url

    2.属性装饰器

    /*
    属性装饰器表达式会在运行时当作函数被调用,传入下列 2 个参数:
      1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
      2.成员的名字
    */
    
    // 定义类装饰器
    function logClass(params: any) {
      return function(target: any) {
        console.log(target);
        console.log(params);
      };
    }
    
    // 定义属性装饰器
    function logProperty(params: any) {
      // target:类的原型对象,attr:属性的名称,这里的 attr 就是 url
      return function(target: any, attr: any) {
        console.log(target);
        console.log(attr);
        // target 相当于 类装饰器中的 target.prototype
        target[attr] = params;// 这里就把 HttpClient 中的 url 改成了 '属性装饰器传递的数据'
      };
    }
    
    @logClass('xxxx')
    class HttpClient {
      @logProperty('属性装饰器传递的数据')
      public url: any | undefined;
    
      constructor() {
      }
    
      getData() {
    
      }
    }

    3.方法装饰器

    /*
      方法装饰器:它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义
      方法装饰会在运行时传入下列三个参数:
        1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        2.成员的名字
        3.成员的属性描述符
    */
    
    
    // 定义方法装饰器
    function logFun(params: any) {
      // 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
      // 2.成员的名字
      // 3.成员的属性描述符
      return function(target: any, methodName: any, desc: any) {
        console.log(target);
        console.log(methodName);
        console.log(desc);
        // 可以扩展属性
        target.name = 'zhangning';
        target.run = function() {
          console.log('跑步');
        };
        // 修改装饰器的方法 把装饰器方法里面传入的所有参数改为 string 类型
        // 1.保存当前的方法
        let oMethos = desc.value;
        desc.value = function(...args: any[]) {
          args = args.map(value => {
            return String(value);
          });
          console.log(args);// args 就是实例传递过来的数组
          oMethos.apply(this, args);
        };
      };
    }
    
    class HttpClient {
      public url: any | undefined;
    
      constructor() {
      }
    
      @logFun('类装饰器传递参数')
      getData(...args: Array<any>): void {
        console.log(args);// args 就是实例传过来的数组
        console.log(this.url);
      }
    }

    4.方法参数装饰器

    /*
      参数装饰器:
        参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列三个参数:
        1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        2.方法的名字
        3.参数在函数参数列表中的索引
    */
    
    function logProp(params: any) {
      return function(target: any, methodName: any, paramsIndex: any) {
        console.log(params);
        console.log(target);
        console.log(methodName);
        console.log(paramsIndex);
        target.name = params;
      };
    }
    
    class HttpClient {
      public url: any | undefined;
    
      constructor() {
      }
    
      getData(@logProp('uuid')uuid: any): void {
        console.log(uuid);
      }
    }
    
    let hc: any = new HttpClient();
    hc.getData(123);
    console.log(hc.name);

    5.装饰器的执行顺序

    // 装饰器的执行顺序
    function logClass1(params: string) {
      return function(target: any) {
        console.log('类装饰器1');
      };
    }
    
    function logClass2(params: string) {
      return function(target: any) {
        console.log('类装饰器2');
      };
    }
    
    function logAttribute(params?: string) {
      return function(target: any, attrname: any) {
        console.log('属性装饰器');
      };
    }
    
    function logMethod(params?: string) {
      return function(target: any, attrname: any, desc: any) {
        console.log('方法装饰器');
      };
    }
    
    function logparams1(params?: string) {
      return function(target: any, attrname: any, desc: any) {
        console.log('方法参数装饰器1');
      };
    }
    
    function logparams2(params?: string) {
      return function(target: any, attrname: any, desc: any) {
        console.log('方法参数装饰器2');
      };
    }
    
    // 4.最后执行类装饰器,先执行下面的,再执行上面的
    @logClass1('zhangning')
    @logClass2('xxx')
    class HttpClient {
      // 1.首先执行属性装饰器
      @logAttribute()
      public url: string | undefined;
    
      constructor() {
      }
    
      // 2.其次执行方法装饰器
      @logMethod()
      getData() {
        return true;
      }
    
      // 3.接着执行方法参数装饰器,执行顺序是从后往前
      setData(@logparams1() attr1: any, @logparams2() attr2: any) {
    
      }
    }
    
    let hc: any = new HttpClient();
    
    /*
    打印结果:
      属性装饰器
      方法装饰器
      方法参数装饰器2
      方法参数装饰器1
      类装饰器2
      类装饰器1
    */
  • 相关阅读:
    Layabox记录坑
    爬虫 Beautifulsoup 常用笔记
    opencv +python 提取roi目标区域全部像素的值 得出上下限 均匀值
    opencv + python 读取像素点 BGRtoRGB 以及注意事项
    pyinstaller打包python+opencv 无法在别人电脑上正常运行 问题所在:opencv_ffmpeg341_64.dll
    python 绝对路径相对路径
    面向对象编程-OOP-一张图看懂类和实例的基本用法
    python3 _笨方法学Python_日记_DAY7
    儋州“炰米”:美味的特制粮食
    PHP学习步骤
  • 原文地址:https://www.cnblogs.com/zhangning187/p/tszsqzn187210414.html
Copyright © 2020-2023  润新知