装饰器
特殊的类型声明,它能够附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器。
装饰器的写法:普通装饰器(无参)、装饰工厂(可传参)
装饰器是过去几年中js 最大的成就之一,已是ES7的标准特征之一。
普通类装饰器
类装饰器是在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或者替换类定义。
//定义装饰器
function logClass(params:any){
console.log(params:any);
//这里的params 就是当前类
}
@logClass //调用装饰器
class HttpClient{
constructor(){
}
getData(){
}
}
打印结果: ![]()
那么已知是当前类,那么就可以操作该类,可以扩展,修改这个类。
//定义装饰器
function logClass(params:any){
console.log(params:any);
//这里的params 就是当前类
params.prototype.apiUrl = 'xxx';
params.prototype.run = function{
console.log("--------run---------");
}
}
@logClass //调用装饰器
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
http.run();
带参数的类装饰器(装饰器工厂)
//定义装饰器工厂
function logClass(params:string){
return function(target:any){
console.log(target);
console.log(params);
}
target.prototype.apiUrl = params; //属性装饰器
}
@logClass("www.baidu.com") //调用装饰器
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
通过打印可以看到,将字符串hello 赋值给了params,将对象赋值给了target.
类装饰器重载构造函数
装饰器表达式会在运行时当做函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,他会使用提供的构造函数来替换类的声明。
function logClass(target:any){
console.log(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();
属性装饰器
属性装饰表达式会在运行时当做函数被调用,传入下列两个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
//类装饰器
function logClass(params:string){
return function(target:any){
console.log(target);
console.log(target);
}
}
//属性装饰器
function logProperty(params:any){
return function(target:any,attr:any){
console.log(target);
console.log(attr);
target[attr] = params;
}
}
@logClass('xxx')
class HttpClient{
@logProperty("http://www.baidu.com")
public apiUrl:string | undefined;
constructor(){
}
getData(){
console.log(this.apiUrl);
}
}
属性装饰器 中打印的 target就是当前对象, 而attr 就是属性 apiUrl,所以可以根据
target[attr] = params;
来修改属性。
方法装饰器
方法装饰器它会被应用到方法的属性描述符上,可以来监视,修改或者替换方法定义。
方法装饰器会在运行时传入下列3个参数:
1、对静态成员来说是累的构造函数,对于实例成员是累的原型对象。
2、成员的名字。
3、成员的属性描述符。
//方法装饰器
function logmethod(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
target.apiUrl = 'xxxx';
target.run = function(){
console.log(this.url);
}
}
}
class HttpClient{
public apiUrl:string | undefined;
constructor(){
}
@logmethod('www.baidu.com')
getData(){
}
}
var http:any = new HttpClient();
console.log(http:apiUrl);
http.run();
同理,target 还是这个原型对象,methodName就是getData 即方法名称, desc是个对象,对象中的value 就是方法名称。
演示:用方法装饰器修改方法,将方法装饰器里面传入的所有参数改为string 类型。
原理:修改desc.value
//方法装饰器
function logmethod(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
// 1保存当前方法
var oldMethod = desc.value;
desc.value = function(...args:any[]){//用三点运算符来接收传入的数组参数
args = args.map((value)=>{
return String(value);
})
console.log(args);
}
}
}
class HttpClient{
public apiUrl:string | undefined;
constructor(){
}
@logmethod('www.baidu.com')
getData(){
console.log("我是getData里面的方法");
}
}
var http = new HttpClient();
http.getData("123","xxx");

很明显getData方法被重写了。
那么如果想修改原来的getData方法那应该这么写
//方法装饰器
function logmethod(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
// 1保存当前方法
var oldMethod = desc.value;
desc.value = function(...args:any[]){//用三点运算符来接收传入的数组参数
args = args.map((value)=>{
return String(value);
})
console.log(args);
oldMethod.apply(this,args);
}
}
}
class HttpClient{
public apiUrl:string | undefined;
constructor(){
}
@logmethod('www.baidu.com')
getData(){
console.log("我是getData里面的方法");
}
}
var http = new HttpClient();
http.getData("123","xxx");
这里的 oldMethod.apply(this,args); 中的this表示
desc.value = function(...args:any[]){ } ,因为是在当前方法中操作的,所以this 指代当前方法。
而args代表参数,它的整体含义就是,在新的方法中传入参数然后调用原来的方法。

可以很明显的看到,原来的getData方法被成功执行。
如果此时将...args:any[] 参数数组传入原来的getData方法中即代码如下
//方法装饰器
function logmethod(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
// 1保存当前方法
var oldMethod = desc.value;
desc.value = function(...args:any[]){//用三点运算符来接收传入的数组参数
args = args.map((value)=>{
return String(value);
})
console.log(args);
oldMethod.apply(this,args);
}
}
}
class HttpClient{
public apiUrl:string | undefined;
constructor(){
}
@logmethod('www.baidu.com')
getData(...args:any[]){
console.log(args:any);
console.log("我是getData里面的方法");
}
}
var http = new HttpClient();
http.getData("123","xxx");
打印的结果如下

可以看到原来的方法中的参数全部变成了string 类型,
这就是方法装饰器,它可以修改方法,也可以修改传入参数类型。
方法参数装饰器
参数装饰器表达式会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些数据,传入下列三个参数:
1、对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象。
2、参数的名字。
3、参数在函数参数列表中的索引。
//方法参数装饰器
function logparams(params:any){
return function(target:any,paramsName:any,paamsIndex:any){
console.log(params);
console.log(target);
console.log(paramsName);
console.log(paamsIndex);
}
}
class HttpClient{
public apiUrl:string | undefined;
constructor(){
}
getData(@logparams('xxxxx'uuid:any)){
console.log("我是getData里面的方法");
}
}
var http = new HttpClient();
http.getData(123456);

uuid成功被打印。
装饰器执行顺序
//定义装饰器工厂
function logClass1(params:string){
return function(target:any){
console.log('类装饰器1');
}
}
function logClass2(params:string){
return function(target:any){
console.log('类装饰器2');
}
}
//属性装饰器
function logProperty(params?:any){
return function(target:any,attr:any){
console.log('属性装饰器');
}
}
//方法装饰器
function logmethod(params:any){
return function(target:any,methodName:any,desc:any){
console.log('方法装饰器');
}
}
//方法参数装饰器
function logparams1(params:any){
return function(target:any,paramsName:any,paamsIndex:any){
console.log('方法参数装饰器1');
}
}
function logparams2(params:any){
return function(target:any,paramsName:any,paamsIndex:any){
console.log('方法参数装饰器2');
}
}
@logClass1("www.baidu.com")
@logClass2("www.IMOOC.com")
class HttpClient{
@logProperty()//可以不传参
public apiUrl:string | undefined;
constructor(){
}
@logmethod('www.baidu.com')
getData(){
console.log(this.apiUrl);
}
setData(@logparams1('xxxxx'uuid:any),@logparams2('xxxxx'uuid:any)){
console.log(this.apiUrl);
}
}
var http:any = new HttpClient();

装饰器执行顺序
属性》方法》方法参数》类
如果有多个同样的装饰器,它会先执行后面的装饰器。
本文详细介绍了TypeScript的装饰器概念,包括类装饰器、属性装饰器、方法装饰器、参数装饰器,以及它们的执行顺序。装饰器允许在运行时修改或扩展类的行为。文章通过实例展示了如何使用装饰器来改变类、属性、方法和参数的功能,并解释了装饰器的参数和执行流程。
7085

被折叠的 条评论
为什么被折叠?



