TS:装饰器,最大的成就之一

TS:装饰器,最大的成就之一

1. 定义

  • 装饰器:装饰器是一种特殊类型的声明,能够被附加到类声明,方法,属性或者参数上,可以修改类的行为;
  • 装饰器本质是一个方法,可以注入到类、方法、属性参数上来拓展类、方法、属性、参数等功能;
  • 常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
  • 装饰器分为两种:普通装饰器(不可传参)和装饰器工厂(可传参);

2. 类装饰器

  • 类装饰器在类声明之前被声明,用于类构造函数,可以用来监控、修改、替换类的定义。

  • 普通装饰器模式

    // 类装饰器
    function logClass(params : any){
          
          
        // params就是当前类
        console.log(params);
        params.prototype.url = '动态扩展的属性';
        params.prototype.run = ()=>{
          
          
    		console.log('动态扩展方法');
        }
    }
    
    @logClass
    class HttpClient {
          
          
        constructor() {
          
          
        }
    }
    
    let http : any= new HttpClient();	//打印 HttpClient {}
    console.log(http.url);	//打印 动态扩展的属性
    http.run(); 	// 打印 动态扩展的方法
    
  • 装饰器工厂模式

    function logClass(params:string){
          
          
        
        return function(target : any){
          
          	//target为当前类
            console.log(target);
            
            console.log(params);	// params为参数
            target.prototype.url = params;
        }
    }
    
    @logClass('hello')
    class HttpClient{
          
          
        constructor(){
          
          
            
        }
    }
    
    let http = new HttpClient();
    console.log(http.url);	// 打印 hello
    
  • 重载类的构造函数

    // 重载构造函数
    function logClass(target){
          
          
        console.log(target);
        
        return class extends target{
          
          
            url : string = '我是修改后的url';
            getData(){
          
          
                console.log(this.url + '.');
            }
            setData(api : string){
          
          
                this.url = api;
            }
        }
    }
    
    @logClass
    class HttpClient{
          
          
        public url : string | undefined;
        constructor(){
          
          
            this.url = "我是构造函数里的url"
        }
        getData(){
          
          
            console.log(this.url);
        }
    }
    
    let http : any = new HttpClient();
    http.getData();		// 打印 我是修改后的数据
    

3. 属性装饰器

  • 属性装饰器接收两个参数:

    1. 对于静态成员来说,是类的构造函数;对于实例成员来说,是类的原型对象;
    2. 成员名称;
    // 类装饰器
    function logClass(params:string){
          
          
        
        return function(target : any){
          
          	//target为当前类
            console.log(target); 
            console.log(params);	// params为参数
            target.prototype.url = params;
        }
    }
    // 属性装饰器
    function logProperty(params:any){
          
          
        return function (target : any,attr : any){
          
          	
            console.log(target);	// 类的原型对象
            console.log(attr);		// 属性的名称
            
            target[attr] = params;
        }
    }
    
    @logClass('hello')
    class HttpClient{
          
          
        @logProperty('heihei')
        public url : any | undefined;
        constructor(){
          
          
            
        };
        getData (){
          
          
            console.log(this.url);
        }
    }
    
    let http = new HttpClient();
    console.log(http.url);	// 打印 heihei
    

4. 方法装饰器

  • 同样的,方法装饰器可以用来监视、修改、替换方法的定义;

  • 接收三个参数:

    1. 对于静态成员来说是类的构造函数,对于实例成员来说是原型对象;
    2. 成员名字;
    3. 成员的属性描述符;
    // 方法装饰器
    function getMethod(params : any){
          
          
        return function(target:any,methodName : any,desc : any){
          
          
            console.log(target);
            console.log(methodName);
            console.log(desc);
    
            target.name = 'xxx';
            target.run  = ()=>{
          
          
                console.log('run');
            }
        }
    }
    class HttpClient{
          
          
        public url : string;
        constructor() {
          
          
        }
        @getMethod('http://www.baidu.com')
        getData(){
          
          
            console.log(this.url);
        };
    }
    
  • 修改原方法:

    // 方法装饰器
    function getMethod(params : any){
          
          
        return function(target:any,methodName : any,desc : any){
          
          
            console.log(target);
            console.log(methodName);
            console.log(desc);
    
            target.name = 'xxx';
            target.run  = ()=>{
          
          
                console.log('run');
            }
    
            // 保存当前方法
            let omethod = desc.value;
            desc.value = function (...args : any[]){
          
          
                args = args.map((value)=>{
          
          
                    return String(value);
                })
                console.log(args);
                // 在新替换的函数里执行原函数
                omethod.apply(this,args);
            }
        }
    }
    class HttpClient{
          
          
        public url : string;
        constructor() {
          
          
        }
        @getMethod('http://www.baidu.com')
        getData(...args : any[]){
          
          
            console.log("我是getData里的方法");
        };
    }
    
    let http = new HttpClient();
    http.getData('yivi');
    

5. 方法参数装饰器

  • 方法参数装饰器表达式在运行时会被当作函数来调用,可以使用参数装饰器为类的原型增加一些元素数据:

    1. 对于静态成员来说是类的构造函数,对于实例成员来说是原型对象;
    2. 方法的名称;
    3. 参数在函数的参数列表的索引;
    // 方法参数装饰器
    function logParams(params : any){
          
          
        return function (target : any,methodName : any,paramsIndex : any){
          
          
            console.log(params);
            console.log(target);
            console.log(methodName);
            console.log(paramsIndex);
            target.api = params;
        }
    }
    
    class HttpClient {
          
          
        public url : string;
        constructor() {
          
          
        }
        getData(@logParams('uuid') uuid : any){
          
          
            console.log(uuid);
        }
    }
    
    let http = new HttpClient();
    http.getData('12345');
    console.log(http.api);
    

6. 装饰器的执行顺序

  • 属性装饰器>>方法装饰器>>方法参数装饰器>>类装饰器;

  • 同类装饰器从下到上执行;

  • 读者可以通过上面例子自行实现装饰器顺序实例。

猜你喜欢

转载自blog.csdn.net/yivisir/article/details/109738785