专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

一文搞懂typescript的装饰器

装饰器是一种特殊类型的声明,它能够附加到类、类的函数、类属性、类函数的参数上,以达到修改类的行为

一、装饰器的种类

  • 1、根据装饰器的位置
    • 类装饰器
    • 类函数装饰器
    • 类属性装饰器
    • 类函数参数装饰器
  • 2、根据装饰器是否有参数
    • 无参装饰器(一般装饰器)
    • 有参装饰器(装饰器工厂)

二、类的装饰器

  • 1、类装饰器的写法
    function desc(target) {
      console.log('---------------类的装饰器参数 start------------------');
      console.log(target); // 输出 [Function: Person]表示当前装饰的类
      console.log('---------------类的装饰器参数 end------------------');
    }

    @desc // 使用装饰器
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    }

    let p = new Person('哈哈', 20);

  • 2、使用类的装饰器扩展类的属性和方法
    function desc(target) {
      console.log('---------------类的装饰器参数 start------------------');
      console.log(target);
      console.log('---------------类的装饰器参数 end------------------');
      return class extends target{ // 在react高阶组件中经常看到这种写法
        gender = '男';
        say() {
          console.log(this.name, this.age, this.gender);
        }
      }
    }

    @desc
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);
    p.say();

    /*
    ---------------类的装饰器参数 start------------------
    [Function: Person]
    ---------------类的装饰器参数 end------------------
    class_1 { name: '哈哈', age: 20, gender: '男' }
    哈哈 20 男
    */

  • 3、使用装饰器修改类的构造函数(构造函数的重载、方法重载)
    function desc(target) {
      return class extends target{
        name = '我是重载后的';
        sayHell() {
          console.log('我是重载后的', this.name);
        }
      }
    }

    @desc
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor() {
        this.name = '哈哈';
        this.age = 20;
      }

      sayHell() {
        console.log('hello word', this.name);
      }
    }

    let p = new Person();
    console.log(p);
    p.sayHell();

  • 4、装饰器工厂的写法
    function desc(params: string) {
      return function (targe: any) {
        console.log('---------------参数说明 start------------------');
        console.log('params', params);
        console.log('target', targe);
        console.log('---------------参数说明 end------------------');
        // 直接在原型上扩展一个属性
        targe.prototype.apiUrl = params;
      }
    }

    @desc('http://www.baidu.com')
    class P {
      say() {
        console.log('说话')
      }
    }

    let p:any = new P();
    console.log(p.apiUrl);

三、类函数装饰器

它应用到方法上,可以用来监视、修改、替换该方法

  • 1、定义方式
    function desc(target, key, descriptor) {
      console.log('---------------类的装饰器参数 start------------------');
      console.log('target', target); // Person { say: [Function] } 表示类的原型
      console.log('key', key); // 被装饰的函数名
      console.log('descriptor', descriptor); // 被装饰的函数的对象属性
      console.log('---------------类的装饰器参数 end------------------');
    }

  • 2、使用
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      @desc
      say() {
        console.log('说的方法')
      }
    }

  • 3、在装饰器中添加类的原型属性和原型方法
    function desc(target, key, descriptor) {
      target.gender = '男';
      target.foo = function () {
        console.log('我是原型上的方法')
      }
    }

    // 测试代码
    let p = new Person('哈哈', 20);
    console.log(p);
    console.log(Person.prototype);
    p.say();
    console.log(p.gender); // 使用p原型链上的属性
    p.foo() // 调用了p原型链上的方法

  • 4、使用装饰器拦截函数的调用(替换)
    function desc(params: string) {
      return function (target: any, key: string, descriptor: {[propsName: string]: any}) {
        // 修改被装饰的函数的
        let method = descriptor.value;
        descriptor.value = function (...args: Array<any>) {
          args = args.map(it => String(it));
          console.log(args);
          // method.apply(this, args);
        }
      }
    }
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      @desc('装饰器上的参数')
      say() {
        console.log('说的方法')
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);
    p.say(123, 23, '你好');

  • 5、使用装饰器拦截函数的调用(附加新的功能)
    function desc(params: string) {
      return function (target: any, key: string, descriptor: {[propsName: string]: any}) {
        // 修改被装饰的函数的
        let method = descriptor.value;
        descriptor.value = function (...args: Array<any>) {
          args = args.map(it => String(it));
          console.log(args);
          method.apply(this, args);
        }
      }
    }
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      @desc('装饰器上的参数')
      say(...args) {
        console.log('说的方法', args)
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);
    p.say(123, 23, '你好');

四、类属性装饰器

  • 1、定义方式
    function desc(target, name) {
      console.log('---------------类属性装饰器的参数 start------------------');
      console.log('target', target, target.constructor); // 表示类的原型
      console.log('name', name); // 表示被装饰属性名
      console.log('---------------类属性装饰器的参数 end------------------');
    }

    class Person {
      public name: string | undefined;
      public age: number | 0;

      @desc
      private gender: string | undefined;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);

  • 2、在装饰器中修改属性值
    function desc(target, name) {
      target[name] = '女';
    }

    class Person {
      public name: string | undefined;
      public age: number | 0;

      @desc
      public gender: string | undefined;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      say() {
        console.log(this.name, this.age, this.gender);
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);
    p.say();

五、类函数参数的装饰器

参数装饰器表达式会在运行时候当做函数被调用,以使用参数装饰器为类的原型上附加一些元数据

  • 1、使用方式
    function desc(params: string) {
      return function (target: any, key, index) {
        console.log('---------------参数装饰器 start------------------');
        console.log(target); // 类的原型
        console.log(key); // 被装饰的名字
        console.log(index); // 序列化
        console.log('---------------参数装饰器 end------------------');
      } 
    }
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      say(@desc('参数装饰器') age: number) {
        console.log('说的方法')
      }
    }

    let p = new Person('哈哈', 20);
    console.log(p);
    p.say(20);

  • 2、为类的原型上添加一些东西
    function desc(params: string) {
      return function (target: any, key, index) {
        console.log('---------------参数装饰器 start------------------');
        console.log(target); // 类的原型
        console.log(key); // 被装饰的名字
        console.log(index); // 序列化
        target.message = params;
        console.log('---------------参数装饰器 end------------------');
      } 
    }
    class Person {
      public name: string | undefined;
      public age: number | 0;

      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      say(@desc('参数装饰器') age: number) {
        console.log('说的方法')
      }
    }

    let p: any = new Person('哈哈', 20);
    console.log(p);
    p.say(20);
    console.log(p.message)

六、几种装饰器的执行顺序

  • 1、测试代码
    function logCls(params: string) {
      return function (target: any) {
        console.log('4.类的装饰器');
      }
    }

    function logMehod(params: string) {
      return function (target: any, key: string, descriptor: {[propsName: string]: any}) {
        console.log('3.类的函数装饰器');
      }
    }

    function logParams(params: string) {
      return function (target: any, name: string) {
        console.log('1.类属性装饰器');
      }
    }

    function logQuery(params: string) {
      return function (target: any, key: string, index: number) {
        console.log('2.函数参数装饰器');
      }
    }

    @logCls('类的装饰器')
    class Person{
      @logParams('属性装饰器')
      public name: string | undefined;

      @logMehod('函数装饰器')
      getData(@logQuery('函数参数装饰器') age: number, @logQuery('函数参数装饰器') gender: string) {
        console.log('----');
      }
    }

  • 2、运行结果
    1.类属性装饰器
    2.函数参数装饰器
    3.类的函数装饰器
    4.类的装饰器

未经允许不得转载:搜云库技术团队 » 一文搞懂typescript的装饰器

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们