装饰器

Typescript和Es6引入了类的概念,也有类装饰器这样的东西,ts已作为试验性特性予以支持。

ps: 文档:https://www.w3cschool.cn/typescript/typescript-decorators.html
操练场:https://www.typescriptlang.org/play/index.html?experimentalDecorators=true#code/

装饰器工厂

1
2
3
4
5
function color(value: string) { // 这是一个装饰器工厂
return function (target) { // 这是装饰器,target属于被装饰对象
// do something with "target" and "value"...
}
}

装饰器特点

  • 多个装饰器可以同时应用到同一个声明上(1. 由上至下依次对装饰器表达式求值。2.求值的结果会被当作函数,由下至上依次调用。)

类装饰器

装饰在类身上的,可以监控类的属性变化,或者给类注入属性,例如一下例子,我们为这个类增加了工具方法来打日志,从而对日志这个方法进行一个总控制。

  • 装饰器参数:为类的构造函数本身。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
      function log(value: string) { 
    return function (constructor: Function) {
    console.log('run when load this js');
    constructor.prototype.logInfo = function (message: string) {
    console.log(`log-${value}`, message);
    }
    }
    }
    @log('info')
    class Greeter {
    greeting: string;
    constructor(message: string) {
    this.greeting = message;
    }
    greet() {
    console.log('greet');
    return "Hello, " + this.greeting;
    }
    }

    const greeter = new Greeter('1');
    greeter.greet();
    greeter.logInfo('今天天气不错');

    ---- 运行结果入下

    console:10 run when load this js
    console:21 greet
    console:12 log-info 今天天气不错

    方法装饰器

  • 可以在执行方法前后切面做一些事情AOP

  • 参数:
    对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
    成员的名字。
    成员的属性描述符。

  • 有个问题不是很理解:为什么装饰器重写方法后返回target[propertyKey]或者target就可以覆盖原方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     // aop 写法可以控制方法前后
    function log(value: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    // console.log('params:', target, propertyKey, descriptor);
    const origin = target[propertyKey];
    // aop
    target[propertyKey] = function(...args: any[]) {
    console.log('before method run')
    let result = origin.apply(this, args)
    console.log('after method run')
    return result;
    }
    return target[propertyKey];
    }
    }
    class Greeter {
    greeting: string;
    constructor(message: string) {
    this.greeting = message;
    }
    @log('info')
    greet() {
    console.log('greet');
    return "Hello, " + this.greeting;
    }
    }

    const greeter = new Greeter('1');
    greeter.greet();

    ----------------- 直接写,切在方法前

    function log(value: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('before run ');
    }
    }
    class Greeter {
    greeting: string;
    constructor(message: string) {
    this.greeting = message;
    }
    @log('info')
    greet() {
    console.log('greet');
    return "Hello, " + this.greeting;
    }
    }

    const greeter = new Greeter('1');
    greeter.greet();

    属性装饰器

  • 修饰属性的, 主要作用是给属性注入值,不用构造函数传递

  • 参数:
    对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
    成员的名字。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function injectValue (target: any, propertyKey: string) {
    console.log('target:',target, propertyKey)
    console.log(target[propertyKey]);
    target[propertyKey] = 'xixi';
    }
    class Greeter {
    @injectValue
    public greeting: string;
    constructor(message: string) {
    // this.greeting = message;
    }
    greet() {
    console.log('greet:', this.greeting);
    return "Hello, " + this.greeting;
    }
    }

    const greeter = new Greeter('pikun');
    greeter.greet();

    参数装饰器