【TS学习笔记】装饰器

最近在自学 TypeScript , 发现装饰器这个内容,还是有挺多知识点需要厘清的,因此将学习中的笔记记录如下,方便自查,也希望各路大牛不吝赐教,嘻嘻 (●’◡’●)
ts中的装饰器的分类,大致分为,类装饰器属性装饰器方法装饰器参数装饰器,下面会对这些装饰器做一下简单的介绍,最后我们再来对比一下这些装饰器的执行顺序。
1. 类装饰器

// 类装饰器
// 可以把逻辑放在装饰器上去实现,主体类部分只实现属性和方法的定义等等
namespace ClassDecorator{ // namespace 命名空间,避免变量或方法污染
    function addNameEat(constructor:Function) {
        constructor.prototype.name = 'holly';
        constructor.prototype.eat = function () {
            console.log('eat');
        }
    }
    @addNameEat
    class Person{
        name!: string;
        eat!: Function;
        constructor() {}
    }

    let p:Person = new Person();
    console.log(p.name); // holly
    p.eat(); // eat
}
// 类装饰器工厂
// 可以实现装饰器中接受参数,原理与装饰器一样,都是把逻辑放在装饰器上去实现,主体类部分只实现变量定义等等
// 而且不论是利用类装饰器还是类装饰器工厂实现的属性跟方法,都是挂载在原型上的
namespace ClassDecoratorFatoty { // 命名空间  可以避免变量名冲突
    function addNameEatFactory(name: string) {
        return function addNameEat(constructor:Function) {
            constructor.prototype.name = name;
            constructor.prototype.eat = function () {
                console.log('eat');
            }
        }
    }
    @addNameEatFactory('jiagou')
    class Person{
        name!: string;
        eat!: Function;
        constructor() {}
    }
    let p:Person = new Person();
    console.log(p.name); // jiagou
    p.eat(); // eat
}

// 类装饰器还可以用作替换类
namespace ClassDecoratorReplace{
    // 出于类型安全考虑  替换的类中的属性或者方法,只能多不能少
    function replaceClass(constructor: Function) {
        return class{
            name!: string;
            eat!: Function;
            age!: number;
        }
    }
    @replaceClass
    class Person{
        name!: string;
        eat!: Function;
        constructor() {}
    }
    let p:Person = new Person();
    console.log(p.name);
}
  1. 属性装饰器
// 属性装饰器 在运行时会被当做函数被调用
// 可以装饰属性 也可以装饰方法
namespace PropertyDecorator {
    // 装饰实例属性时,target是构造函数的原型 propertyKey要装饰的属性
    function upperCase(target: any, propertyKey: string) {
        // console.log(target); // Person {}
        // console.log(propertyKey); // name
        let value = target[propertyKey]; // 获取到name值
        const getter = () => value;
        const setter = (newVal:string) => {value = newVal.toUpperCase()}
        if(delete target[propertyKey]) {
            Object.defineProperty(target, propertyKey, {
                get: getter,
                set: setter,
                enumerable: true,
                configurable: true
            });
        }
        
    }
    // 装饰静态属性时,target是构造函数本身
    function staticPropertyDecorator(target: any, propertyKey: string) {
        // console.log('装饰静态属性的装饰器', target); // [Function: Person]
    }

    function noEnumerable(target: any, propertyKey: string, descriptor:PropertyDescriptor) {
        // console.log(target, propertyKey);
        descriptor.enumerable = false; // 修改实例的可枚举属性
    }
    function toNumber(target: any, propertyKey: string, descriptor:PropertyDescriptor) {
        /** descriptor打印出来的信息
         * {
            value: [Function: sum],
            writable: true,
            enumerable: false,
            configurable: true
            }
         */
        console.log(descriptor);
        let oldMethod = descriptor.value;
        descriptor.value = function(...args: any[]) {
            args = args.map(item => parseFloat(item));
            return oldMethod.apply(this, args);
        }
    }
    class Person{
        @upperCase
        name: string = 'holly'; // 实例属性
        @staticPropertyDecorator
        static age: number; // 静态属性
        @noEnumerable
        getName() { console.log(this.name); } // 实例方法
        @toNumber
        sum(...args: any[]) {
            return args.reduce((acc: number, cur: number) => acc+cur, 0);
        }
    }
    let p: Person = new Person();
    console.log(p.name); // HOLLY
    console.log(p.sum('1', '2', '3', '4')); // 10
}
  1. 参数装饰器
namespace ParamDecorator {
    // target 如果是静态成员就是构造函数本身   非静态成员就是构造函数的原型
    // methoName 方法名称
    // paramsIndex 参数的索引
    function addPwd(target: any, methodName:any, paramsIndex: number){
        // 这里的target是构造函数的原型
        console.log(target, methodName, paramsIndex); // Person {} login 1
        target.age = 10;
    }
    class Person {
        age!: number;
        login(username: string, @addPwd password: string){
            console.log(this.age, username, password);
        }
    }
    let p: Person = new Person();
    p.login('holly', '12434'); // 10 holly  12434
}
  1. 装饰器的执行顺序
// 装饰器的执行顺序
namespace DecoratorSort {
    // 类装饰器
    function ClassDecorator1() {
        return function(target: any) {
            console.log('ClassDecorator1', target);
        }
    }
    function ClassDecorator2() {
        return function(target: any) {
            console.log('ClassDecorator2', target);
        }
    }
    function PropertyDecorator(name: string) {
        return function(target: any, propertyKey: string) {
            console.log('PropertyDecorator', target, propertyKey);
        }
    }
    function MethodDecorator() {
        return function(target: any, propertyKey: string) {
            console.log('MethodDecorator', propertyKey, target);
        }
        
    }
    function ParamterDecorator() {
        return function(target: any, methodName: string, index: number) {
            console.log('ParamterDecorator', methodName, index);
        }
    }
    @ClassDecorator1()
    @ClassDecorator2()
    class Person {
        @PropertyDecorator('name')
        name!: string;
        @PropertyDecorator('age')
        age: number = 10;
        @MethodDecorator()
        hello(@ParamterDecorator() p1: string, @ParamterDecorator() p2: string){
            console.log(p1, p2);
        }
    }
}

/**
 * 输出顺序
 *  PropertyDecorator Person {} name
    PropertyDecorator Person {} age
    ParamterDecorator hello 1
    ParamterDecorator hello 0
    MethodDecorator hello Person {}
    ClassDecorator2 [Function: Person]
    ClassDecorator1 [Function: Person]
    规律总结:
    1. 类装饰器是最后执行的,而且越靠近类的装饰器越先执行
    2. 方法和方法参数中的装饰器 是先执行参数 再执行方法
    3. 方法和属性装饰器,是谁在前,就先执行谁
 */
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值