TypeScript-特色功能之装饰器

前言

TypeScript系列文章:

本篇文章就来介绍一下TypeScript中最特殊的装饰器,装饰器对于使用JavaScript的同学肯定非常陌生,其实我对装饰器也充满了疑问,下面是我在学习TypeScript装饰器中的一些笔记和个人理解。

现在装饰器在react,vue的源码中都有应用,所以是一个非常重要的概念。

注意:本篇文章需要对JavaScript中的原型和原型链有一定的了解,因为很多概念都涉及到了原型和原型链,所以如果不清楚原型和原型链的话,可以看这篇文章:JavaScript:原型链和原型对象

装饰器(Decorators)

什么是装饰器

  • 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
  • 通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
  • 常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器。
  • 装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
  • Javascript里的装饰器目前处在建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。

注意:装饰器是一项实验性特性,在未来的版本中可能会发生改变。

若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项。

命令行:

tsc --target ES5 --experimentalDecorators

tsconfig.json:

{
    "compilerOptions": {
        "target": "ES5",
        "experimentalDecorators": true
    }
}

类装饰器

类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的类)。

类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。

function logMethos(constructor: object) {
  console.log(constructor);
  // params为当前类
}

@logMethos
class Student {
  private name: string = "张三";
}

装饰器工厂

可以传入参数。

function logMethos(value: string) {
    return function (target: any) {
        target.prototype.name = value;
    }

}

@logMethos("张三")
class Student {
    name: string | undefined;
    constructor() {
        console.log("构造函数");
    }

}
let s = new Student();
console.log(s.name);

这种装饰器在实际应用的过程中,使用的是非常多的,比如vue的vue-property-decorator库中的类装饰器@Component,可以在括号中使用js在vue中的语法。

@Component({})
export default class Home extends Vue {}

修改构造函数

function logMethos(target: any) {
    return class extends target {
       name:any = "李四"
    }

}

@logMethos
class Student {
    name: string | undefined;
    constructor() {
        this.name = "张三"
    }

}
let s = new Student();
console.log(s.name);

属性装饰器

function logProperty(params:any) {
    return function(target:any,attr:any) {
        console.log(params);
        console.log(target);
        console.log(attr);
        target[attr] = params; //修改属性
    }
}

class Student{
    @logProperty("张三")
    name:String | undefined;
}

方法装饰器

function logMethos(params: any) {
    return function (target: any, methodName: any, desc: any) {
        let oMethod = desc.value;
        desc.value = function (...args: any[]) {//修改修饰器方法

            args = args.map((value)=> {
                return String(value);
            })
            console.log(args);

        }
    }
}

class Student {
    name: String | undefined;
    @logMethos("张三")
    getData() {

    }
}

let s= new Student();
s.getData("123","211");

参数装饰器

function logParams(params: any) {
    return function (target: any, paramsName: any, paramsIndex: any) {
        console.log(params);
        console.log(target);
        console.log(paramsName);
        console.log(paramsIndex);
    }
}

class Student {
    name: String | undefined;
   
    getData(@logParams("213") uid:any) {

    }
}

let s= new Student();

装饰器执行顺序

属性→方法→方法参数→类

为什么要用装饰器

看了上面的例子,你可能还是不知道为什么要用装饰器。

其实使用装饰器是为了使代码不具有那么强的侵入性,而且一旦装饰器使用得当,那么代码在后期维护起来会变得非常轻松。

比如下面两个例子:

最后

本来这篇文章在一个月之前就写的差不多了,但是那个时候我几乎完全不能理解为什么要使用装饰器,什么情况下使用装饰器。

在我使用了一段时间的TypeScript后,发现装饰器是一个非常棒的功能,虽然我自身用的很少,但是使用别人已经写好的装饰器,让代码显得更加的简介和明了。

我个人是非常喜欢装饰器的,而且装饰器绝对是一个值得掌握的技能,不仅使代码编写起来更加容易,同时在后期维护的时候也会更加轻松一些。

文档

装饰器