使用 TypeScript 自定义装饰器给类的属性增添监听器 Listener
语法
type PropertyDecorator =
(target: Object, propertyKey: string | symbol) => void;
target:直接写在类的属性上?
看个例子:
function capitalizeFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function observable(target: any, key: string): any {
// prop -> onPropChange
const targetKey = "on" + capitalizeFirstLetter(key) + "Change";
target[targetKey] =
function (fn: (prev: any, next: any) => void) {
let prev = this[key];
Reflect.defineProperty(this, key, {
set(next) {
fn(prev, next);
prev = next;
}
})
};
}
class C {
@observable
foo = -1;
@observable
bar = "bar";
}
const c = new C();
c.onFooChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))
c.onBarChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))
c.foo = 100; // -> prev: -1, next: 100
c.foo = -3.14; // -> prev: 100, next: -3.14
c.bar = "baz"; // -> prev: bar, next: baz
c.bar = "sing"; // -> prev: baz, next: sing
编译通不过:
一种解决办法是,添加下图这种 dummy 方法,这种方法不推荐,因为缺乏灵活性:
另一种方法较通用,即为类添加通用的所谓的 index signature:
语法如下:
意思是类 C 可以拥有任意的属性,且属性名称为 string
运行时,target 的类型为类 C 的构造函数:
key 为属性名:
在下图第 15 行代码,直接给 C 的构造函数注入一个新的 on 监听函数:
这个监听函数的函数体,直到代码44行 onXXX 被调用时才会被执行:
给 C 对象实例的 foo 属性使用 Reflect.defineProperty API 设置一个 set 方法。
这样,每次该实例的 foo 属性被修改时,就触发其 set 函数:
在 set 函数实现体内,首先调用应用开发人员传入的 回调函数 fn,然后将 this[key] 设置为新的值 next.
运行时,c.foo = 100, 会导致 Reflect.defineProperty 注册在 foo 属性的 set 方法被触发:
在 set 函数里,我们再也不能访问到 C 实例的 foo 或者 bar 属性,但是通过闭包,能访问到其修改之前的原始值:
更多Jerry的原创文章,尽在:"汪子熙":
Jerry Wang的SAP技术专栏
SAP成都研究院开发专家,SAP社区导师,SAP中国技术大使
884 声望
1.6k 粉丝
推荐阅读
Spartacus i18n 配置相关代码的工作原理
具体而言,这段代码中,我们首先导入了 translations 和 translationChunksConfig 变量,它们是Spartacus应用程序中用于存储翻译相关信息的变量。
JerryWang_汪子熙
2022大前端总结和2023就业分析
我在年前给掘金平台分享了《2022年热点技术盘点》的前端热点,算是系统性的梳理了一下我自己对前端一整年的总结。年后,在知乎上看到《前端的就业行情怎么样?》,下面都是各种唱衰前端的论调,什么裁员,外包化...
i5ting赞 27阅读 2.3k评论 4
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...
边城赞 17阅读 6.7k评论 3
vue-property-decorator使用手册
@Component 装饰器可以接收一个对象作为参数,可以在对象中声明 components ,filters,directives等未提供装饰器的选项,也可以声明computed,watch等
似曾相识赞 17阅读 29.6k评论 7
JS 函数式概念: 管道 和 组合
微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势,学习途径等等。本文 GitHub [链接] 已收录,有一线大厂面试完整考点、资料以及我的系列文章。
前端小智赞 9阅读 921
Vue3 + Vite2 + TypeScript + Pinia(Vuex)+JSX 搭建企业级开发脚手架【开箱即用】
随着Vue3的普及,已经有越来越多的项目开始使用Vue3。为了快速进入开发状态,在这里向大家推荐一套开箱即用的企业级开发脚手架,框架使用:Vue3 + Vite2 + TypeScript + JSX + Pinia(Vuex) + Antd。废话不多话,...
阳晨@赞 11阅读 3.4k
掌握 TypeScript:20 个提高代码质量的最佳实践
本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一时间和你分享前端行业趋势,学习途径等等。更多开源作品请看 GitHub [链接] ,包含一线大厂面试完整考点、资料以及我的系列文章。
前端小智赞 9阅读 915
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。