请教一下 TypeScript 装饰器的用法

278 天前
 sunny1688

import EventEmitter from 'node:events';

const emitter = new EventEmitter();

const on = (eventName: string) => {
    return (target: Object, methodName: string, descriptor: PropertyDescriptor) => {

        // 直接这样绑定可以运行
        emitter.on(eventName, descriptor.value);


        const value = descriptor.value;

        // 如果是这种写法,就可以有 this ,但不会执行到 get()里面,写了也没用
        return {
            configurable: true,
            enumerable: true,
            get() {
                // 这里的 this 就是 Logic ,但根本不会执行到这里面
                const bound = value.bind(this);
                emitter.on(eventName, bound);
                return bound;
            }
        } as PropertyDescriptor
    }
}


const off = (eventName: string) => {
    return (target: Object, methodName: string, descriptor: PropertyDescriptor) => {
        // todo
    }
}

class Logic {
    value = 1;

    @on('eventKey')
    onStart() {
        console.log('onStart');

        // this 是 undefined ,我想在把 this 绑定到当前对象上,应该如何在装饰器上处理?
        console.log(this);  //
    }


    @off('start')
    onDestroy() {

    }
}

new Logic();

// 某些时刻会触发,这里是否模拟一下
emitter.emit('eventKey');

1444 次点击
所在节点    程序员
14 条回复
kevin97
278 天前
这样试试呢?添加 bind

```js
// 直接这样绑定可以运行
emitter.on(eventName, descriptor.value.bind(target));
```
sunny1688
278 天前
target 不是 Logic 实例 @kevin97
NICE20991231
278 天前
方法装饰器负责添加元信息(就是一个配置...),具体的由 class 装饰器实现,可以试下
zbinlin
278 天前
zsj1029
278 天前
Ts 的装饰器还是实验阶段吧,没正式发布吧
hsfzxjy
278 天前
帮楼主一整套写好了

https://www.typescriptlang.org/play?experimentalDecorators=true&target=99#code/MYewdgzgLgBAogNwKZigYQIYBssCMPADWAshgA4DSSAnjALwwDK1AtriFgBQCUA3AFBRqZJPGSpMOfEVJl6MWQB5oAJwCWYAOYAaGADEArmGBQ14ANoBdAHwD+oSLHDzOScVAByGFkgBcMVQ1NbnprGE4oDBVNJCh-AHlcACskE10fKAALEAATLx9-QK1dHKQIYHUyKBAVfwAFFRARFSEAETKKtSqakLowgG9+GGGYB2gYQiwMCAh5SOjYmGmYI0IwEAB3MCXZ-phzRBR0bDwCEnIqakt-Q4kT6XO5AF8BEZgsReBcWRv3SVOZORXiM1AAzcKJFImAB0mWm8S2nEm0wguluxykZ1kl24IUGbzeX1k8mRMwOf3uWIuNEswOGTxgSCwEFE+IJwyJ5HkYCQGwUQKG7JgkNSUGhpVBGiQDSaSBa1CRUxmaIpmMBlBoujZQpGDklmgMKgwuA+-lB2BZ2kFOuGKAMPiNJr8MHNzKQVptIwQ2AMzs5ZGtBKe3EDT0DY1gX1mDH90JiUFc7nySBCAH5U-taeHcBBoWQDBBMpxSuVKtUVNDvVhfXxs7JoSyE24jsndFHa2H7OBxgAlJCaNTQOVIHL-B4QS7yZhsDg8ARCEQwPsDocqEdjs7R-bN1DJwpQdTFUa4fyGYymcCWKwCUFGExmbZrldQOUAQRw6IgnBAyX8GDA1C6E+g4vmutThGA3jOkUOgumAp53heYC9GECAgGoOR4oGYIQskoqwvCiI-kkujLiBw6jpSRATjQuIwGuUCGmAdKjN2sDAauI7+GRnGUWqhBbtega3ueD4wHCYA5B8MrVAuSCcAAHn+AFYTqEYwGQjTVPIIowvGMkgHJ8SgoptY6jhnCaYZID0HQDBgAYOAhAxTEsW8ElSdKWmGcI8lWdUZlChZACEulinCEAImAlneSqRwbuqOLObErmBoSbHHj8YjxVRjzyP5IDkjl-HYjSbm6t85DQqCNRwAQRacFGug7p4UEoceuY1SodXAEWXyhDA2o2up7BGDk8hfNCuAaDk37JIFnocaBcqJi2UG6KNkkLTaS0UXmBZFuYLWtjAm05JY21vMG21hu5-6eQZclzUk21heKSCSjyMrNEIz2kf25FrnxAICZcWppSMdoOsapouha7oQxy4D6oaMPOq6lqIzAVa+v4u1Ax6IzBvwnYifezhGPj75YJ+z3KYBKxgPjcr+JwkEFAEB5BG2J76IhD7tWhGGqbqGXMzk3EA7xCUCfIxHmDxy3A+OlxZm84vVbV9WcJw5js+6x4XQNlNS8tKhs+tx64ixGsfFoWTyAADAInbAEqswAEKDYGmlqN6L70UgGA5OAWC0DjogMAATM7gYAALgJwABELWvknIZvKCACMPDe2p3YcEg0JYCAmjJx7lY+pHSe6Fkg615kg6V9WKYsWGrvuzAaCMgpL6SZ7ecjL7-uiGuweh+HVdR-IAAsUcsQn0Up+4acZyMoJR7nQ3pZAhfF6XydoM3vrT3QNcwHXuYR1HN0k-w-Bk0hgfPsO5vHVB+6HrBXwIaJ4Ai8MAA9IAmAgBCK0APtGgBouUAG9ygALm0ADGK4YC4fH3mXAABorCiMBFAABJ+iTX1k8MIXVGTuBgEnPB78fBPCTmgteQCQEQJgYAYBjAAUrkg3eKCS7oIAJJgDQoQIIMA8EEKgk8aEEi6HZh4HfB+-MKZM1Nq-Vau4P6cy-jzX+5NkKDwYWAqBcDAAAqRwiAe9uGcDQQAVUUS-IG2CRG4GhIQ4hNRSFHHIZQpMYjaEhk7F2ThRdzEAHIAC0YSwlBJDCNbkvIYAewEFTD87gvy4CAkosCtYTa2OprTVJjNmYqFrGMMxB9QnhJCZE-x4xgAxL5GgBJ6ScnJMamk2xcpMk2MBk0o4X5gC6CyYDdpAhilcNKeUip3AgA
hsfzxjy
278 天前
@hsfzxjy 如果你想在构造时就自动注册,那就在构造函数里手动调用一下 registerAllEvents
yetrun
278 天前
装饰器尚在试验阶段,没有大规模铺开来用,别用。尤其是自己发布的包或者项目,别用,可能过几年就用不了了。
zjccc
278 天前
装饰器是作用在原型链上的,所以拿不到 this 。
可以使用装饰器配合 Reflect-metadata 添加元数据(本质上和上面搞一个全局的 map 差不多),然后构造函数里面通过 this 拿到 prototype 上的方法,再调用 .call(this)
tianzi123
277 天前
别用二货玩意,都要被淘汰的玩意
hzzhzzdogee
277 天前
angular 不是大规模使用装饰器吗, 这个语法还是稳定的吧?
nzbin
277 天前
@hzzhzzdogee Angular 的装饰器只是语法糖,主要用于传递元数据,编译之后是没有的
sunny1688
277 天前
@hzzhzzdogee
@tianzi123

正如 12 楼说的那样,装饰器只是语法糖,那些 @符号编译后是没有的,现在都 stage-3 阶段了,不会淘汰的
sunny1688
277 天前
@hsfzxjy 很感谢!

不过还是没有达到我想要的版本,我用 stage-3 版本实现好了,只需要 @on('xx') 就能自动订阅事件,不需要在构造函数里面手动注册

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/962479

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX