TS笔记 - 07泛型装饰器 @log

装饰器

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

常见装饰器方法:类装饰器、属性装饰器、方法装饰器、参数装饰器

写法:普通装饰器(无法传参) 装饰器工厂(可传参)

装饰器是过去几年中JS最大的成京之一,已是ES7的标准特性之一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 装饰器 就是一个方法
// 类装饰器 不要加分号 无参普通装饰器
function logClass(params:any){
console.log(params);
//params 就是当前类
params.prototype.apiUrl='http://';
params.prototype.run=function(){
console.log('我是一个run方法');
};
}
@logClass
class HttpClient(){
constructor(){

}
getData(){

}
}

var http:any = new HttpClient();
http.apiUrl; // http://
http.run();


// 带参 装饰器工厂
function logClass(params:string){
return function(target:any){
console.log(target); // 类 HttpClient
console.log(params); // hello

target.prototype.text=params;
}
}

@logClass('hello')
class HttpClient(){
constructor(){
//
}
getData(){
//
}
}

var http:any = new HttpClient();
http.text; // hello

1、类装饰器:重截构造函数的例子

如果类装饰器返回一个值,它会使用提供的构造函数替换类的声明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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(){
apiUrl : string | undefined;
constructor(){
this.apiUrl = '我是构造函数里面的apiUrl';
}
getData(){
console.log(this.apiUrl);
}
}
var http:any = new HttpClient();
http.getData();

2、属性装饰器

对于静态成员来说是类的构造函数,对于实例成员是类的原型对象

成员名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 类装饰器
function logClass(params:any){
return function(target:any){

}
}

// 属性装饰器 target 类的原型对象
function logProerty(params:any){
return function(target:any,attr:any){
console.log(target); // HttpClient
console.log(attr); // http://
target[attr] = params; //!!重点 难点 对实例成员来说是类的原型对象
}
}

@logClass('xxx')
class HttpClient(){
@logProerty('http://')
public url:any|undefined;
constructor(){
}
getData(){
console.log(this.url);
}
}

var http:any = new HttpClient();
http.url; // http://

3、方法装饰器

修改当前实例的属性和方法

修改当前里的参数修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target); //HttpClient
console.log(methodName); // getData
console.log(desc.value); // 当前方法

target.url = 'xxx';
var oMethod = desc.value;
desc.value = function(...args:any[]){
args = args.map((value)=>{
return String(value);
})
oMethod.apply(this,args);
}
}
}
class HttpClient(){
public url:string | undefined;
constructor(){
}
@get('http://www.baidu.com') // !!重点
getData(...args:any[]){
console.log('我是getdata里的方法');
}
}
var n = new HttpClient();
http.getData(123,'123123');

4、方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入以下三个参数

1、对表态成员来说是类的构造函数,对实例成员是类的原型对象

2、方法的名字

3、参数在函数参数列表中的索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function logParams(params:any){
return function(target:any,methodName:any,paramsIndex:any){
console.log(params); // uuid
console.log(target); //HttpClient 当前类原型对象
console.log(methodName); // getData 当前方法名称
console.log(paramsIndex); // 0 当前索引

}
}
class HttpClient(){
public url:string | undefined;
constructor(){
}
getData(@logParams('uuid') uuid:any){ // !!重点
console.log(uuid); // 123
}
}
var http = new HttpClient();
http.getData(123);

执行顺序

属性 》 方法 》 方法参数 》 类

如果有多个同样的装饰器,它会先执行后面的!!!