You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从单个Observable<Person[]>生成两个修改后的Observable<Person[]>实例

问题原因分析

  • tap 是副作用操作符,本身不会对流发射的数据做转换,仅适合执行日志、外部调用等逻辑,不符合数据转换的使用场景,多订阅时的时序问题会导致你遇到的取到原始数据的问题。
  • 之前用 map 出错是因为直接修改了原始 Person 对象的属性:JS 中对象为引用类型,原始流发射的数组内的对象是多订阅共享的,第一个流修改原对象后,第二个流拿到的就是已经被修改的数据,自然结果不符合预期。

实现方案

核心逻辑有两点:

  1. 原始流使用 share 操作符做多播,避免多次订阅触发重复的上游逻辑
  2. 转换数据时返回新的对象拷贝,不修改原始数据,两个流的转换逻辑互不影响

完整代码示例

import { Observable, of } from 'rxjs';
import { map, share } from 'rxjs/operators';

// 你贴的接口名为ToolfaceData,和前文的Person描述不一致,统一修正为Person即可
export interface Person {
    age: number;
    name: string;
}

// 原始源流,添加share做多播
const source$: Observable<Person[]> = of([
  { age: 2, name: 'Anne' },
  { age: 5, name: 'Bob' }
]).pipe(share());

// 第一个流:age统一加2,每次返回新对象,不修改原数据
const ageAdd2$ = source$.pipe(
  map(personList => 
    personList.map(p => ({
      ...p, // 浅拷贝原有属性
      age: p.age + 2
    }))
  )
);

// 第二个流:age统一减2,同样返回新对象
const ageMinus2$ = source$.pipe(
  map(personList => 
    personList.map(p => ({
      ...p,
      age: p.age - 2
    }))
  )
);

效果验证

分别订阅两个流即可得到预期结果:

ageAdd2$.subscribe(console.log); 
// 输出:[{age:4, name:'Anne'}, {age:7, name:'Bob'}]

ageMinus2$.subscribe(console.log);
// 输出:[{age:0, name:'Anne'}, {age:3, name:'Bob'}]

注:如果你的Person对象包含深层嵌套属性,把浅拷贝替换为深拷贝逻辑即可,当前单层结构用扩展运算符...足够。

内容的提问来源于stack exchange,提问作者g1wonwon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 19:54:03