Nest 装饰器的理解

96 阅读4分钟

最近在学习使用 nest 框架开发公司管理系统,nest 大量使用了装饰器这个东西,所以在此记录并分享学习到的东西。

一、 什么是装饰器

装饰器是一种特殊的类型声明,能够附加到类型,方法,属性或者参数上,可以修改类的行为。装饰器的好处:

  1. 好的装饰器就是代码注释;
  2. 帮助代码解耦;
  3. 提高代码的复用性;
  4. 代码更加简洁, 更便于阅读;

二、装饰器分类

装饰器 是一个函数,它可以通过 @funName 在类、方法、访问符、属性、参数上,对它们进行包装,然后返回一个包装后的目标对象(类、方法 、访问符、属性、参数)。

1. 类装饰器

类装饰器应用于类的构造函数,可以用来监视,修改,和替换类定义

function logClass(param:any){
    console.log(param);

    #修改类的属性和方法
    param.prototype.aaa = "xxx";
    param.prototype.getMessage = () => {
        console.log('getMessage');
    }
}

@logClass
class A {
    constructor() {}
    
    getData() {
        console.log('getData');
    }
}

# 可以看到动态扩展属性方法已经成功了
const a = new A();
console.log((a as any).aaaa);   // xxx
console.log((a as any).getMessage()); // getMessage
2. 装饰器工厂

只要在普通装饰器的基础上return一个函数即可变成装饰器工厂

function logClass(param:any){
    console.log(param);

    # param 变成了传进来的值,而 return 的函数的参数 target 就变成了类 A,修改类的属性和方法
    return function(target) {
        target.prototype.aaa = "xxx";
        target.prototype.getMessage = () => {
            console.log('getMessage');
        }
    }
    
}

@logClass("装饰器工厂")
class A {
    constructor() {}
    
    getData() {
        console.log('getData');
    }
}

# 可以看到动态扩展属性方法已经成功了
const a = new A(); // 装饰器工厂
console.log((a as any).aaaa);   // xxx
console.log((a as any).getMessage()); // getMessage

总结,类装饰器一般是一个函数,分为装饰器工厂和普通装饰器,主要是原理就是类的构造函数会通过参数传入该装饰器(函数),在该函数上对类做一系列的扩展,加强该类

3. 属性装饰器

属性装饰器接受两个参数,第一个是类的原型对象!!!!第二个是属性名字。通过拿到原型对象去加强该属性。而类装饰器拿到的参数是类的构造函数,不是原型对象

function logClass(param:any){
    console.log(param);

    # 类的原型对象,属性名
    return function(target:any, name:string) {
        console.log('target': target);
        console.log(name);
        target[name] = param;
    }
    
}

class A {
    @logClass("BBBB")
    public bb: string | undefined;
    constructor() {}
    
    getData() {
        console.log('getData');
    }
}

# 可以看到动态扩展属性方法已经成功了
const a = new A(); // BBBB
a.getData();   // target:function A(){}  bb
4. 方法装饰器

方法装饰器会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰器接受三个参数:

  1. 对于静态方法来说是类的构造函数;对于实例方法则是类的原型
  2. 方法名
  3. 成员的属性描述符
function logClass(param:any){
    console.log(param);

    # 类的原型对象,方法名,成员的属性描述符
    return function(target:any, name:string, desc:any) {
        console.log('target': target);
        console.log('name':name);
        console.log('desc':desc);
    }
    
}


class A {
    constructor() {}
    @logClass("实例成员方法装饰器")
    getDataA() {
        console.log('getDataA');
    }
     @logClass("静态成员方法装饰器")
    static getDataB() {
        console.log('getDataB');
    }
}

# 可以看到静态成员拿到的是构造函数,实例成员拿到的是类的原型对象
const a = new A(); 
a.getData();   
5. 方法参数装饰器

可以使用参数装饰器为类的原型增加一个数据,也可以加强和修改对应的形参。传入下列三个参数:
1 跟方法装饰器一样,静态传构造,实例传原型。
2 参数的名字
3 参数在方法中的索引(第几位)

function logClass(param:any){
    console.log(param);

    # 类的原型对象,方法名,参数在方法中的索引
    return function(target:any, name:string, index:any) {
        console.log('target': target);
        console.log('name':name);
        console.log('index':index);
    }
    
}


class A {
    constructor() {}
    @logClass("实例成员方法装饰器")
    getDataA(
    a:any,
    b:andy,
    @logClass("实例成员方法装饰器") c: any
    ) {
        console.log('getDataA');
    }
     
    static getDataB(
    a:any,
    b:andy,
    @logClass("静态成员方法装饰器") c: any
    ) {
        console.log('getDataB');
    }
}

# 装饰器(一般是函数)通俗的就是用来加强其修饰的对象,其修饰的对象通过参数传入其中,再在装饰器中执行一系列操作,扩展对象的功能
const a = new A(); 
a.getData(1,2,3,4);   

总结,装饰器的执行顺序:即属性装饰器->方法装饰器->方法参数装饰器->类装饰器这

参考:blog.csdn.net/lin_fightin… www.jianshu.com/p/fc6a81593…