【TS基础】个人学习记录10-牛逼的装饰器

概念

装饰器可以附加给类的声明中属性,方法上等,动态的对他们进行扩展。

装饰器是一项实验性特性,在vscode中使用的话会提示:

对修饰器的实验支持功能在将来的版本中可能更改。在 “tsconfig” 或 “jsconfig” 中设置 “experimentalDecorators” 选项以删除此警告。

使用

普通装饰器(无传参)

// 装饰器是用一个函数去定义
function logClass(param: any){
    // param这个参数能拿到对应加了装饰器的类是个function
    param.age = 1; // 这样加是没有用的
    param.prototype.fn = function(): void {} // 拓展了fn这个方法
}

@logClass // 装饰器要这样加到类上
class Person {
    name: string
    constructor(name: string) {
        this.name = name
    }
}

let p = new Person('xiaoming')
p.fn() // 虽然能执行但是编译器提示没有这个新添的方法

装饰器工厂(可传参)

// 装饰器是用一个函数去定义
function logClass(param: string){
    // 此时param这个参数拿到的是传进来的参数
    return function(target: any){
        // target拿到的才是加了装饰器的类
    }
}

@logClass('param') // 装饰器要这样加到类上
class Person {
    name: string
    constructor(name: string) {
        this.name = name
    }
}

let p = new Person('xiaoming')

对比着前面的普通装饰器(无传参)来看

类的重载(类装饰器)

const extension = (constructor: Function) => {
    constructor.prototype.meeting = () => { // 这里写重载
        console.log('重载');
    }
}

@extension
class Employee {
    public name!: string
    constructor(name: string) {
        this.name = name
    }
    meeting() {}  
}

let e: any = new Employee('nick')
e.meeting()  // 重载

属性装饰器

以上都是属于类装饰器的使用方法,接下来是针对类属性的装饰器:

function attrName(params:any) {
    // params为传入的参数
    return function(targetProto: any, attr: string){
        // 此时targetProto为类的原型(静态成员来说是类的构造函数,对于实例成员是类的原型对象),attr为加了类中加了装饰器的属性。
        targetProto[attr] = params
    }
}

class Person {
    @attrName('修改1')
    name: string
    @attrName('修改2')
    speak: string | undefined
    constructor(name: string) {
        this.name = name
    }
}

let p = new Person('xiaoming')
console.log(p.name) // 装饰器是类实例化的时候就生效,所以打印出xiaoming
console.log(p.speak) // 修改2

方法装饰器

针对类方法的装饰器:

重写方法

function setFn(params: any){
    return function(target: any, methodName: any, desc: any) {
        // console.log(params) // 传进来的参数
        // console.log(target) // 静态成员来说是类的构造函数,对于实例成员是类的原型对象
        // console.log(methodName) // 加修饰器的方法
        // console.log(desc) // 方法的描述,通过desc.value可以获取对应方法
        desc.value = function(num: number){ // 参数需要这样接收
            console.log(num) 
        }
    }
}
class Person {
    name: string | undefined
    constructor() {}
    @setFn('wow') // 方法修饰器
    fn(){
        console.log(this.name)
    }
}

let p = new Person()
p.fn(2) // 不过这里会有错误提示,所以方法重写的时候,最好和原来的参数写法一致

方法修改

function setFn(params: any){
    return function(target: any, methodName: any, desc: any) {
    	const fn =  desc.value
        desc.value = function(num: number){ // 参数需要这样接收
            console.log(num+99) 
            fn.call(this, num) // 这句话意思是改变this指向,相当于把原来方法的肉填到这
        }
    }
}
class Person {
    name: string | undefined
    constructor() {}
    @setFn('wow') // 方法修饰器
    fn(num: number){
        console.log(num)
    }
}

let p = new Person()
p.fn(2)
// [LOG]: 101 
// [LOG]: 2 

方法参数装饰器

很少用,我觉得了解一下即可

function log(param: string) {
  console.log(param)
  return function (target: any, name: string, index: number) {
    console.log(index)
    // target: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  	// name: 成员的名字
	// descriptor: 成员的属性描述符
  }
}

class Employee {
  fn(@log('IT') department: string, @log('John') name: string) {
    console.log('给参数加上修饰器')
  }
}

装饰器顺序

如果同时声明了类、属性、方法、方法参数装饰器,那么执行的顺序是:

属性---->方法---->方法参数----->类

如果同一种装饰器同时声明多次,那么执行顺序是从下到上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值