装饰器的一些疑问

来源:11-11 【泛型工厂类继承装饰器底层源码】逐行深剖+优化底层 JS 源码

拔凉的望着你

2021-12-06

function classDecorator<T extends { new (...args: any[]): any}>(targetClass: T) {
    class SonClass extends targetClass{
        constructor(...args: any[]) {
            super(...args);
            console.log('我被执行了, SonClass, 我从' + targetClass.name)
        }
        methodOne() {
            console.log(this.id)
        }
    }
    return SonClass
}

@classDecorator
class Order {
    constructor(public id: number) {
    }
    pay() {
        console.log('pay it')
    }
}

let order = new Order(123123) // 这里是调用装饰器的写法
// 在函数上面是封装了一层,调用是会执行一次SonClass的构造函数
// 但是因为SonClass上面有方法methodOne,想在order上面执行methodOne方法时
// order.methodOne()  // Property 'methodOne' does not exist on type 'Order'
// ts会报错,找不到该方法,于是需要写成函数的方式


let sonClass = classDecorator(Order)
new sonClass(123123).methodOne()   // it's work
// 但是我觉得这样写,不是脱离了装饰器的范畴了吗?
// 最开始这样做的初衷是为了在装饰器上面做一些通用操作
// 如果需要用到装饰器的一些公用方法
// 需要去改变装饰器本来的写法,我是有一些疑惑的
写回答

2回答

F_Gump

2021-12-08

1、直接通过classDecorator(Order)构造对象时,编译器在编译的时候就已经确定了classDecorator要处理的对象类型是Order,同时知道classDecorator函数返回SonClass对象。所以你可以访问其中的methodone方法。

2、当使用装饰器@classDecorator时,@classDecorator需要编译后才可以被执行。也就是那个__decorator()方法是编译后产生的,而__decorator只有被执行以后才知道你的Order实际被替换成了SonClass。

所以这两个使用方式造成的结果差异的本质是:1在编译期间就能确认类型;2在执行期间才能确认类型。

至于`需要去改变装饰器本来的写法,我是有一些疑惑的`的疑问你大可不必有,因为装饰器或者装饰器模式本质的意图是为了做切面增强的,就是AOP。不存在这种通过装饰器新增方法的场景,这是违背设计模式的,所以正常是没有这种诉求的。如果真的想增加方法,可以直接通过继承或是采用适配器模式。

希望对你有帮助!


1
1
拔凉的望着你
非常感谢!
2021-12-08
共1条回复

keviny79

2021-12-07

需要看完 方法装饰器 10-16 会理解【尤其是前置,后置方法拦截器】,这个只是对 泛型工厂函数在类装饰器的运用和加深理解做了一个测试。

0
0

晋级TypeScript高手,成为抢手的前端开发人才

轻松驾驭 TypeScript 高级用法, 突破前端成长瓶颈

871 学习 · 425 问题

查看课程