- 装饰器是一种特殊类型的申明,它能够被附加到类申明、方法、属性或参数上,可以修改类的行为
- 通俗的讲,装饰器就是一个方法,可以注入到类、方法、属性或参数上来扩展类、属性、方法、参数的功能
- 常见的装饰器: 类装饰器、属性装饰器、方法装饰器、参数装饰器
- 装饰器的写法: 普通装饰器(无法传参)、装饰器工厂(可以传参)
普通装饰器: 不能传参
// 定义一个装饰器
function logClass(param:any){
console.log(param)//输出:ƒ HttpClient() {}
// 扩展类的属性与方法
param.prototype.apiUrl="xxx"
param.prototype.run=function(){
console.log("动态扩展的run方法")
}
}
@logClass
class HttpClient{
constructor(){}
getData(){
}
}
let h:any = new HttpClient()
h.run()//动态扩展的run方法
装饰器工厂:可以传参
// 定义一个装饰器工厂
// param接收自己传的参数
// target接收类信息
function logClass(param:string){
return function(target:any){
console.log(param,target)//xxx ƒ HttpClient() {}
// 属性扩展
target.prototype.url = param
}
}
@logClass("xxx")
class HttpClient{
constructor(){}
getData(){
}
}
let h:any = new HttpClient()
console.log(h.url)//xxx
装饰器组合:多个装饰器可以同时应用到一个声明上,就像下面的示例:
//书写在同一行上:
@f @g x
//书写在多行上:
@f
@g
x
类装饰器:类装饰器在类声明之前被声明(紧靠着类声明),类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
function decorObj(param:any) {
console.log(param) // param就是createObj这个类
return class extends param{
name:any = '我是修改后的名字';
getName() {
console.log(this.name + '222222')
}
}
}
@decorObj
class createObj {
public name:string | undefined;
constructor(name:string) {
this.name = name;
}
getName() {
console.log(this.name)
}
}
const obj = new createObj('张山');
obj.getName(); // 打印 我是修改后的名字222222
// 通过这个打印结构告诉我们,createObj的构造函数和getname这个方法都被修改了
方法装饰器:方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
- 成员的属性描述符。
function getMethods(params:string) {
return function(p1:any, p2:any, p3:any) {
// console.log(p1) // 参数一:对于静态方法来说是类的构造函数,对于实例成员来说是原型对象prototype
// console.log(p2) // 参数二:成员的名字
// console.log(p3) // 参数三:成员的描述信息
let modifyMethods = p3.value; // p3.value就是createMethods中的modifyData这个方法
p3.value = function (...args:any[]) { // 改写createMethods中的modifyData这个方法
args = args.map(item => String(item)) // 强制将modifyData方法中的参数转换为string类型
console.log(args)
modifyMethods.apply(this, args) // 相当于在修改后的方法中又执行了原本的modifyData这个方法
}
}
}
class createMethods{
public name:string | undefined
constructor() {}
@getMethods('123')
modifyData(...args:any[]) { // 修改方法的时候,就在那个方法前面加一个装饰器
console.log(args,'哈哈哈')
}
// @getMethods('456')
getName() {
console.log('111')
}
}
const me = new createMethods();
me.modifyData('456',45454)
访问器装饰器:访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义。TypeScript不允许同时装饰一个成员的get和set访问器。访问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
- 成员的属性描述符。
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() { return this._x; }
@configurable(false)
get y() { return this._y; }
}
function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
属性装饰器:属性装饰器声明在一个属性声明之前(紧靠着属性声明),属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
function decorAttr(params:string) {
console.log(params, 11);
return function (target:any, attr:string) {
console.log(target) // 注意这里target是CreateClass的prototype
console.log(attr) // attr就是name
// 注意上面的name是在构造函数中初始化的,这里实在属性装饰器中初始化的
target[attr] = params
}
}
class CreateClass {
@decorAttr('通过属性装饰器给name初始化')
public name:string | undefined;
constructor(){}
getName() {
console.log(this.name);
}
}
const obj = new CreateClass();
obj.getName()
参数装饰器:参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器只能用来监视一个方法的参数是否被传入,参数装饰器的返回值会被忽略。参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
- 参数在函数参数列表中的索引。
// 方法参数装饰器
// 在执行方法时,调用方法参数装饰器,给类的原型对象增加属性,也可以修改参数
function logParams(param:any){
return function(target:any,methodName:any,paramIndex:any){
console.log(param,target,methodName,paramIndex)
// 给原型对象增加属性
target.id=param
}
}
class HttpClient{
url:string|undefined
get(@logParams("uuid")uuid:any){
console.log("类里面的实例方法"+uuid)
}
}
let h:any = new HttpClient()
h.get(12233)//类里面的实例方法12233
console.log(h.id)//uuid
总结
装饰器可以对类、方法、属性、参数进行修改、扩展、替换等操作
执行顺序:属性装饰器->方法装饰器->方法参数装饰器->类装饰器
同类装饰器执行顺序:由下向上、由里及外、由后往前