TypeScript学习笔记(六) | 装饰器Decorators

241 阅读3分钟

| 什么是装饰器

定义
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,@expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

通俗来讲就是在不动原来的方法的前提下,扩展方法的功能
是es7的标准特性

本质
装饰器本质上是一个函数@expression 的形式其实是一个语法糖

注意
在 TS 中,装饰器仍然是一项实验性特性,未来可能有所改变,所以如果要使用装饰器,需要在 tsconfig.json 的编译配置中开启experimentalDecorators,将它设为 true

装饰器的写法有两种

  1. 普通装饰器(不可传参)
  2. 装饰器工厂(可传参)

| 用法

  1. 类装饰器
    给类动态扩展参数和方法
// 创建一个装饰器
function myDec(params:any) {
    console.log(params); // 当前类Myclass
    params.prototype.apiUrl = 'xxxx' // 给Myclass扩展(装饰)了一个属性   
}
@myDec  // 使用装饰器
class Myclass {
    constructor() {
    }
    getData() {
    }
}

重载类的属性和方法例子

function myDec(params:any) {
    console.log(params); // 当前类Myclass
    return class extends target {
        apiUrl:any='我被重载了';
        
        getData() {
            console.log('我也被重载了')
        }
    }
}
@myDec  // 使用装饰器
class Myclass {
    public apiUrl:string |undefined
    constructor() {
        this.apiUrl = '我是构造函数的属性'
    }
    getData() {
        console.log('我是方法')
    }
}

  1. 装饰器工厂 装饰器工厂可以传参,其他普通装饰器不可以传参,
    装饰器里返回一个方法就是一个装饰器工厂
// 创建一个装饰器工厂 
function logClass(params:string) {
    console.log(params); // 王一博
    return function(target:any) {
        console.log(target); // 当前类 Myclass
        
        // TODO
        target.prototype.name = params
    }
}
@logClass('王一博')  // 使用装饰器工厂并传参
class Myclass {
    constructor() {
    }
    getData() {
    }
}
let wyb = new Myclass()
console.log(wyb.name); // 王一博
  1. 属性装饰器 属性装饰器会在运行时当做函数被调用,传入下列2个参数

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

// 创建一个属性装饰器
function logProperty(params:string) {
    // 两个参数
    return function(target:any,attr:any) {
        console.log(target); // 当前类 Myclass
         console.log(attr); // 当前装饰器传的值 王一博
    }
}

class Myclass {
    @logProperty('王一博')
    public name:any | undefined;
    constructor() {
    }
    getData() {
    }
}
let wyb = new Myclass()
console.log(wyb.name); // 王一博
  1. 方法装饰器 传三个参数

①静态成员是类的构造函数,实例对象是类的原型对象
②成员名字
③成员属性描述符

// 创建一个方法装饰器
function logMethod(params:string) {
    console.log(params); // 王一博
    // 三个参数
    return function(target:any,methodName:any,desc:any) {
        console.log(target); // 当前类 Myclass
         console.log(methodName); // 当前方法name
          console.log(desc);  // Myclass的加了方法装饰器的方法对象
    
    	// 改写方法
    	desc.value = function(..args:any[]){
         	  
            	// 不改写方法,而是继承原来的方法
               desc.value.apply(this,args)   
     	}
    }
}

class Myclass {
    public name:any | undefined;
    constructor() {
    }
    @logMethod('王一博')
    getData() {
    }
}
let wyb = new Myclass()
console.log(wyb.name); // 王一博
  1. 方法参数装饰器 给类的原型增加一些元素数据,传入参数有三

①当前类
②参数名称
③参数在函列表的索引

// 定义一个方法参数装饰器
function logParams(params:any) {
    console.log(params) // 王一博
    return function(target:any,methodName:any,attrIndex:any) {
         console.log(target) // Myclass
         console.log(methodName) // 方法名 getData
         console.log(attrIndex)   // 0
    }
}

class Myclass {
    constructor() {
    }
    getData(@logParams('王一博') name:any) {
    }
}
  1. 装饰器执行顺序 属性装饰器--》方法装饰器(从上到下)--》方法属性装饰器(从右到左)-》类装饰器(从下到上)