bunny学习笔记|TS的类装饰器/属性装饰器/方法装饰器

2022-06-20  本文已影响0人  一只小小小bunny

装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。通俗的装饰器就是一种方法,可以注入到类,方法,属性参数来扩展类,属性,方法,参数的功能。

常见的装饰器有:类装饰器,属性装饰器,方法装饰器,参数装饰器;
装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)

类装饰器

类装饰器:装饰器在类声明之前被声明(紧跟着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或者替换类定义,传入一个参数。

(1)装饰器:(普通装饰器(无法传参))
index.ts

// 装饰器:(普通装饰器(无法传参))
function logClass(params){
    console.log(params);//当前类
//因此我们可以操作这个类
    params.prototype.apiUrl='动态扩展的属性';
    params.prototype.run=function(){
        console.log("我是一个run方法")
    }
}

@logClass
class HttpClient{
    constructor(){}
    getData(){}
}

var http =new HttpClient();
console.log(http.apiUrl);
http.run();//用装饰器给类添加的方法

PS:简单测试的话,可以新建对应的index.html文件,引入js,<script type="text/javascript" src="index.js"></script> ;另外要将ts转化为对应的index.js文件,终端执行法,tsc index.ts [前提是先安装tsc才可以执行]

得到的结果:


类装饰器

(2) 类装饰器:装饰器工厂(可传参)
index.ts

function logClass(params:string){
return function(target:any){
//返回的target就是调用本装饰器的类
    console.log(target,"target");
    console.log(params,"params得到的值");
    target.prototype.apiUrl=params;//将传入的参数赋值给该类的原型扩展属性apiUrl
}
}

@logClass('hello')//调用装饰器同时传入一个string类型的参数
class HttpClient{
    constructor(){}
    getData(){}
}

var http =new HttpClient();
console.log(http.apiUrl);
输出的结果: 类装饰器

(3)类装饰器重载构造函数
类装饰器表达式会运行时当作函数被调用,类的构造函数作为其唯一的参数。如果类装饰器返回一个值,他会使用提供的构造函数来替换类的声明。

function logClass(target:any){
    console.log(target,"target");
    return class extends target{
    apiUrl:any="我时修改后的数据";
    getData(){
        this.apiUrl=this.apiUrl+'---'
        console.log(this.apiUrl);  
    }
  }
}

@logClass
class HttpClient{
    public apiUrl:string|undefined;
    constructor(){
        this.apiUrl='我是构造函数里面的apiUrl';
    }
    getData(){
        console.log(this.apiUrl);
    }
}

var http =new HttpClient();
http.getData();
输出结果: 类装饰器-重载构造函数

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列两个参数:
1.对于静态成员来说是类的狗仔函数,对于实例对象是类的原型对象;
2.成员的名字

index.ts

//属性装饰器
function logProperty(params:any){
    return function(target:any,attr:any){
        console.log(target,"target");
        console.log(attr,"attr");
        target[attr]=params;
    }
}

class HttpClient{

    @logProperty('http://www.baidu.com')
    public url:any|undefined
    constructor(){}
    getData(){
        console.log(this.url);
    }
}

var http:any =new HttpClient();
http.getData();
输出结果: 属性装饰器

对应的index.js代码

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
//属性装饰器
function logProperty(params) {
    return function (target, attr) {
        console.log(target, "target");
        console.log(attr, "attr");
        target[attr] = params;
    };
}
var HttpClient = /** @class */ (function () {
    function HttpClient() {
    }
    HttpClient.prototype.getData = function () {
        console.log(this.url);
    };
    __decorate([
        logProperty('http://www.baidu.com')
    ], HttpClient.prototype, "url");
    return HttpClient;
}());
var http = new HttpClient();
http.getData();

方法装饰器

它会被应用带方法的属性描述符上,可以用来监听、修改、替换、方法定义

方法装饰器运行时传入3个参数:
(1)对于静态成员来说类的构造函数,对于实例成员来说是类的原型对象
(2)成员的名字
(3)成员的属性描述

function logMethod(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target,"--target--");
        console.log(methodName,"--methodName--");
        console.log(desc,"--desc--");

        target.apiUrl = params
        target.run = function(){
            console.log("--这是run--")
        }
    }
}
class HttpClient{
    public url:any | undefined;
    constructor(){}
    @logMethod('www.baidu.com')
    getData(){
        console.log(this.url,"--this.url--")
    }
}
var http:any = new HttpClient()
console.log(http.apiUrl)
http.run()
输出结果: 方法装饰器
使用方法装饰器修改方法
function logMethod2(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target); 
        console.log(methodName);
        console.log(desc);
        console.log(desc.value);

        // !!! 修改装饰器的方法,把装饰器所有传入的参数改为string
        // 1. 保存当前的方法
        var oMethod = desc.value;
        desc.value = function(...args:any[]){
            args = args.map((value)=>{ // map 循环遍历
                return String(value) // 转类型
            })
            console.log(args) // [ 123, 999 ]
            oMethod.apply(this.args) // 用对象冒充来实现 把当前方法和参数传入
        }
    }
}
class HttpClient2{
    public url:any | undefined;
    constructor(){}
    @logMethod('www.baidu.com')
    getData(...args:any){ 
// 将传入的any类型的参数解构
        console.log(args)
        console.log("我是getData里的方法")
        console.log(this.url)
    }
}
var http = new HttpClient2()
http.getData(123,999)
方法参数装饰器
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.apiUrl = params;
       }
   }
   class HttpClient3{
    public url:any | undefined;
    constructor(){}
    getData(@logparams('xxxx') uuid:any){
 // 在方法的参数里面调用装饰器,传入参数,在参数里还需要接收这个参数
        console.log("我是getData里的方法")
    }
}
var http = new HttpClient3()

http.getData(123123);
console.log(http.apiUrl) // xxxx

学习源的链接:
https://blog.csdn.net/weixin_40121676/article/details/105717756?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2

上一篇下一篇

猜你喜欢

热点阅读