装饰器的详细介绍

70 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

类的装饰器

类的装饰器接收唯一一个参数,然后可以扩展这个类的prototype属性,从而扩展类实例的属性,下面代码可以打印‘tom’ ,我的类型是tom


function test(constructor) {
    constructor.prototype.name = 'tom';
    constructor.prototype.show = function () {
        console.log('我的类型是' + this.name)
    }
}


@test
class Person {

}

let p: Person = new Person;
console.log(p.name)
p.show()

上面的写法虽然是实现了,但是ts编译器会认为我们的p没有name属性,也没有show方法,会给我们报错,那么我们在装饰器参数里就要做好类型的声明,才能保证编辑器正常解析。

这代码写的没什么问题,都是编译器不行,理解不了而已


function test<T extends new (...args: any[]) => {}>(constructor: T) {
    return class  extends constructor {
        name: string = '实则棒'
        show() {
            console.log(this.name, '是个大坏蛋')
        }
    }
}

@test
class Person {

}

let p = new Person;
console.log(p.name);
p.show();

上面代码的写法,和下面的写法是一个意思,但是下面这种写法,编辑器认识,不报错,毕竟ts只是实验性特性,ts也没有过多的支持吧

function test<T extends new (...args: any[]) => {}>(constructor: T) {
    return class extends constructor {
        name: string = '实则棒'
        show() {
            console.log(this.name, '是个大坏蛋')
        }
    }
}

const Person = test(class {

})


let p = new Person;
console.log(p.name);
p.show();

方法装饰器

顾名思义 ,方法装饰器就是写在方法前面的,方法装饰器接收3个参数,静态成员的类的构造函数,或者实例成员的类的原型,成员名称,成员的属性描述符

可以理解为第一个参数是表示这是描述哪个对象的,这里第一个参数打印的是Person的原型对象,这个方法实际上是原型对象上的方法

console.log(target===Person.prototype) 打印的是true


function getNameDesc(target,name,desc){
    console.log(target.show())
     console.log(target===Person.prototype)
    console.log(target,name,desc)
}

class Person {
    name: string = '实则棒';
    constructor(name: string) {
        this.name = name;
    }
    @getNameDesc
    getName(): string {
        return this.name
    }
    show() {
        console.log('我的名字是', this.name)
    }
}

当修饰的是静态方法时,第一个参数就不是类的原型对象了,因为静态方法属于是类的属性,所以,target就是Person类 target===Person为true


function getNameDesc(target, name, desc) {
    console.log(target === Person.prototype)
    console.log(target === Person)
    console.log(target, name, desc)
}

class Person {
    name: string = '实则棒';
    constructor(name: string) {
        this.name = name;
    }
    @getNameDesc
    static getName(): string {
        return this.name
    }
    show() {
        console.log('我的名字是', this.name)
    }
}
console.log(Person.prototype)