ES7 decorator详解。
2019-06-24 本文已影响0人
TouchMe丶
装饰器
概念
装饰器是一种特殊类型的声明,他能够被附加到类声明,方法,属性或者参数上。可以修改类的行为。常见的装饰器有:类装饰器,属性装饰器,方法装饰器。装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参).
类装饰器
类装饰器在类声明之前被声明。类装饰器应用于类构造函数,可以用来监视,修改或替换定义。传入一个参数,代表当前类。装饰器可以在不修改类的前提下来扩展类的功能:
//普通装饰器
function logClass(params:any){
//普通装饰器的参数params代表的被装饰器修饰的类
//扩展params的属性和方法
params.prototype.xxx = "xxxxxx";
params.prototype.run = function(){
console.log("我是一个run方法");
}
}
@logClass
class Aclass{
constructor(){}
getData(){}
}
//查看效果
var A = new Aclass();
A.run();
在控制台中,上面会输出"我是一个run方法"的字符串。说明我们的装饰器编写成功了。
下面我们来构建一个可以传参的类装饰器,被称为装饰器工厂。这种装饰器的具体写法就是在装饰器函数内返回一个新的函数,新函数有一个参数target,代表被修饰的类,而上层函数的参数params,则代表了传入的参数。
function logClass(params:string){
return function(target:any){
console.log(target);//代表目标类HttpClient
console.log(params);//代表装饰器工厂传的参数 "hello"
target.prototype.apiUrl = params;
}
}
@logClass("http://www.baidu.com")
class HttpClient{
constructor(){}
getData(){}
}
var http = new HttpClient();
console.log(http.apiUrl);
上面的代码会在控制台打印出"http://www.baidu.com".
接下来,再看另一种情况。修改当前类的构造函数的装饰器。类装饰器表达式会在运行时当做函数被调用,类的构造函数作为其唯一的参数。如果类装饰器返回一个值,它会使用提供的构造函数类替换类的声明。
function logClass(target:any){
console.log(target);
return class extends target{ //target就是下面的httpClient这个类
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();
属性装饰器
属性装饰器表达式会在运行时当做函数被调用,传入下列2个参数:
1.对静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2.成员的名字。
//类装饰器
function logClass(params:any){
return function(target:any){
// console.log(target);//类
// console.log(params);//参数
}
}
//属性装饰器
function logProperty(params:any){
console.log(params);
return function(target:any,attr:any){
//target对静态成员来说是类的构造函数,对于实例成员是类的原型对象
console.log(target);
console.log(attr);
target[attr] = "hahaha";//修改了下面的url
}
}
@logClass("xxxx")
class httpClient{
@logProperty("http://ityinglcn")//装饰下面那个属性url
public url:string | undefined;
constructor(){
}
getData(){
console.log(this.url);
}
}
var http = new httpClient();
http.getData();
方法装饰器
方法装饰器会被应用到方法的属性描述符上 可以用来监视,修改或者替换方法定义。
方法装饰器会在运行时传入下列3个参数:
1.对静态成员来说是类的构造函数,对实例成员来说是类的原型对象。
2.成员的名字。
3.成员的属性描述符。
//扩展当前类HttpClient的实例和方法。
function get(params:any){
return function(target:any,name:any,desc:any){//target这个例子代表了HttpClient类
//扩展当前类HttpClient的实例和方法。
target.apiUrl = "xxx";
target.run = function(val:string){
console.log('run')
}
}
}
class HttpClient{
public url:any | undefined;
constructor(){
}
@get("http://www.itying.com")
getData(){ //这个getData是实例方法 所以拿到的是HttpClient的原型对象
console.log(this.url);
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
http.run();
修改被修饰的方法。
function get(params:any){
return function(target:any,name:any,desc:any){//target这个例子代表了HttpClient类
//修改getData()方法 就要修改desc下面的value 这个value就是被修饰的方法
// console.log(desc.value);
//把getData传入的参数改为string类型
//1.保存当前的方法
var oMethod = desc.value;
//2.修改
desc.value = function(...args:any[]){
args = args.map(item => {
return item.toString();
});
console.log(args);
//如果只是修改 不替换 就用下面的方法 在里面调用oMethod 并且把参数args传入
oMethod.apply(this,args);
};
}
}
class HttpClient{
public url:any | undefined;
constructor(){
}
@get("http://www.itying.com")
getData(...args:any[]){ //这个getData是实例方法 所以拿到的是HttpClient的原型对象
console.log(args);
console.log("我是getData里面的方法");
}
}
var http:any = new HttpClient();
http.getData(123,"xxx");