装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一
针对类的修饰,只有一个参数 target 指类本身 针对静态 属性 方法 方法的参数来讲:第一个参数 target 是指 类本身(也既构造函数本身,注意这里讲的是’构造函数’,因为 javascript 没有类机制,所以用的构造函数模拟实现) 针对实例 属性 方法 方法的参数来讲:第一个参数 target 是指 类的 prototype
请注意,这是非常重要的区别,以下代码演示这些区别
修饰类
function decoClass(target: any) {
// target 就是当前类
target.prototype.apiUrl = '动态扩展的属性';
target.prototype.run = function () {
console.log('我是一个run方法');
};
}
@decoClass
class TestClass {}
const instance: any = new TestClass();
console.log(instance.apiUrl);
instance.run();
修饰属性 [静态 | 实例]
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
function logProperty(params: any) {
return function (target: any, attr: any) {
console.log(target);
console.log(attr);
target[attr] = params;
};
}
class staticDemo {
@logProperty('http://loaderman.com')
// 区别在这里,看这里,看这里
public url: any | undefined;
getData() {
console.log(this.url);
}
}
const staticDemoTest = new staticDemo();
staticDemoTest.getData();
class instanceDemo {
@logProperty('http://loaderman.com')
// 区别在这里,看这里,看这里
static url: any | undefined;
getData() {
console.log(instanceDemo.url);
}
}
const instanceDemoTest = new instanceDemo();
instanceDemoTest.getData();
修饰方法 [静态 | 实例]
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
3、成员的属性描述符。
function decoMethod(params: any) {
return function (target: any, methodName: string, desc: any) {
console.log(target);
console.log(methodName);
console.log(desc);
target.url = params;
target.run = function () {
console.log('run');
};
};
}
// 实例方法修饰
class instanceMehodClass {
// 区别在这里,看这里看这里
public url: string | undefined;
@decoMethod('http://www.loaderman,com')
getData() {
console.log(this.url);
}
}
const http: any = new instanceMehodClass();
http.getData();
// 静态方法修饰
class staticMethodClass {
static url: string | undefined;
@decoMethod('http://www.loaderman,com')
static getData() {
console.log(staticMethodClass.url);
}
}
staticMethodClass.getData();
修饰方法的参数 [静态 | 实例]
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、方法的名字。
3、参数在函数参数列表中的索引。
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 paramsClass {
public url: any | undefined;
getData(@logParams('xxxxx') uuid: any) {
console.log(uuid);
}
}
const http: any = new paramsClass();
http.getData(123456);
console.log(http.apiUrl);
装饰器执行顺序
属性》方法》方法参数》类
如果有多个同样的装饰器,它会先执行后面的, 至于工厂装饰器,按洋葱模型执行
function logClass1(params: string) {
return function (target: any) {
console.log('类装饰器1',target, params);
};
}
function logClass2(params: string) {
return function (target: any) {
console.log('类装饰器2',target, params);
};
}
function logAttribute1(params?: string) {
return function (target: any, attrName: any) {
console.log('属性装饰器1',target, attrName, params);
};
}
function logAttribute2(params?: string) {
return function (target: any, attrName: any) {
console.log('属性装饰器2',target, attrName, params);
};
}
function logMethod1(params?: string) {
return function (target: any, attrName: any, desc: any) {
console.log('方法装饰器1', target, attrName, desc, params);
};
}
function logMethod2(params?: string) {
return function (target: any, attrName: any, desc: any) {
console.log('方法装饰器2' ,target, attrName, desc, params);
};
}
function logParams1(params?: string) {
return function (target: any, attrName: any, desc: any) {
console.log('方法参数装饰器1' ,target, attrName, desc, params);
};
}
function logParams2(params?: string) {
return function (target: any, attrName: any, desc: any) {
console.log('方法参数装饰器2' ,target, attrName, desc, params);
};
}
@logClass1('http://www.loaderman.com/api')
@logClass2('xxxx')
class HttpClient {
@logAttribute1()
@logAttribute2()
public apiUrl: string | undefined;
@logMethod1()
@logMethod2()
getData() {
return true;
}
setData(@logParams1() attr1: any, @logParams2() attr2: any) {
console.log(attr1, attr2);
}
}
const http: any = new HttpClient();
http.getData();