如何在RxJS中扩展map运算符?实现带对象克隆的自定义运算符
自定义RxJS运算符mapToVM实现结果深克隆
当然可以通过包装map运算符来实现你的需求,只需要在执行传入的投影函数后,对返回结果进行JSON.parse(JSON.stringify())深克隆即可。这样订阅者拿到的始终是原始对象的副本,不会影响store中的源数据。
修改后的完整代码如下:
import { map, Observable, OperatorFunction, Subject } from "rxjs"; console.clear(); const store = new Subject<{ company: { id: number } }>(); // 对比:原生map返回原对象引用,修改会影响store store.pipe(map((s) => s.company)).subscribe((company) => { console.log("原生map返回的对象:", company); company.id = 2; console.log("修改后store内的对象:", store.value); // 输出 { company: { id: 2 } } }); function mapToVM<T, R>( project: (value: T, index: number) => R ): OperatorFunction<T, R> { return map((value, index) => { // 先执行用户传入的投影逻辑 const result = project(value, index); // 对对象类型进行深克隆,原始值直接返回 if (typeof result !== "object" || result === null) { return result; } return JSON.parse(JSON.stringify(result)); }); } // 使用自定义mapToVM,返回克隆后的对象,修改不影响store store.pipe(mapToVM((s) => s.company)).subscribe((company) => { console.log("mapToVM返回的克隆对象:", company); company.id = 3; console.log("修改后store内的对象:", store.value); // 仍然输出 { company: { id: 2 } } }); store.next({ company: { id: 1 } });
关键说明:
- 在
mapToVM内部,我们通过map运算符包装了用户的投影函数,先得到投影结果,再对结果做深克隆处理。 - 增加了对非对象类型(如字符串、数字、null等)的判断,避免无意义的克隆操作,提升性能。
JSON.parse(JSON.stringify())是一种简单的深克隆方式,但注意它无法处理函数、Symbol、循环引用等特殊类型,如果你的场景包含这些情况,需要替换为更健壮的深克隆方法(比如lodash的cloneDeep)。
内容的提问来源于stack exchange,提问作者Jon Sud
相关产品推荐
相关产品推荐

