javascript - 在 array.prototype.map(在 RxJS 管道中)中返回副本或操作原始对象之间的区别
问题描述
我正在开发一个 Angular 9、RxJS 6 应用程序,并且对管道主题值的不同结果和在该管道中进行单位转换有疑问。
请看一下这个 stackblitz。在那里,在backend.service.ts
文件内部,创建了一个可观察对象,它进行一些“单位转换”并返回所有提交给 _commodities 主题的内容。如果您查看该convertCommodityUnits
函数,请注意我注释掉了工作示例,而是采用了我最初解决它的方式。
我的问题:当您使用屏幕上的取消订阅按钮并再次订阅时,当使用仅覆盖对象而不进行复制的“转换解决方案”时,HTML中的值被转换多次,因此管道不使用主体提供的原始数据。如果您使用其他代码,因此在里面创建商品对象的克隆convertCommodityUnits
,它会像预期的那样工作。
现在,我不明白为什么这两种转换数据的方式如此不同。我知道一个直接操作数据,因为 js通过共享调用并且返回一个新对象。但是传递给convertCommodityUnits
函数的对象是由函数创建的array.prototype.map
,所以它不应该覆盖任何东西,对吧?我希望 RxJS 使用发送给主题的原始最后一个数据传递给管道/映射运算符,但在示例中似乎并非如此,对吧?
如何/为什么在这里多次转换值?
这或多或少是一个后续问题:Angular/RxJS 手动更新管道主题(即使没有数据更改),“rxjs 管道中的单位转换”,所以它是相同的设置。
解决方案
当您使用时,您会map
获得数组的新参考。但是您不会在新生成的数组(数组的浅拷贝)中获得新对象,因此您正在改变元素内的数据。
在解构解决方案中,因为数组中的每个对象只有原始类型,所以每次调用转换方法时都会为数组生成全新的元素(这很重要:不仅是新数组,还有新元素在数组中 => 您已经执行了数组的深层复制)。因此,您不会连续累积每个订阅中的值。
这并不意味着您在提供的 stackblitz 演示中使用的 1 级解构解决方案在所有情况下都适用。我已经看到这个错误很多,特别是在需要你不改变存储数据的redux模式框架中,比如ngrx、ngxs等。如果你的数组中有复杂的对象,那么1级解构会'数组的每个元素中的所有嵌入对象都保持不变。我认为用例子来描述这种行为更容易:
const obj1 = {a: 1};
const array = [{b: 2, obj: obj1}];
// after every newArray assignment in the below code,
// console.log(newArray === array) prints false to the console
let newArray = [...array];
console.log(array[0] === newArray[0]); // true
newArray = array.map(item => item);
console.log(array[0] === newArray[0]); // true
newArray = array.map(item => ({...item}));
console.log(array[0] === newArray[0]); // false
console.log(array[0].obj === newArray[0].obj); // true
newArray = array.map(item => ({
...item,
obj: {...item.obj}
}));
console.log(array[0] === newArray[0]); // false
console.log(array[0].obj === newArray[0].obj); // false
推荐阅读
- android - 使用文件传输插件从科尔多瓦的 s3 服务器下载图像文件
- android - 为什么没有数据库文件
- cryptography - 了解明文组合规则、加密算法和 2 个密文块,如何找到明文和密钥
- azure - Azure 持久功能:JsonSerializationException 通过将复杂对象从触发器传递到协调器
- python - 每次我按下一个键时 CLI 清除屏幕
- wordpress - 单个 URL mod_rewrite 不断回到原始 URL
- java - Elasticsearch spring 实现错误
- r - 将因子分成 R 列
- java - 如果我们添加新分区,我们会在 Kafka Streams 中丢失消息吗?
- ios - 如何设置 AWS Appsync 请求超时限制 || AWSAppSync 客户端未提供回调