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