为什么用Set实现的数组差异检测对fetch返回的对象数组失效?
问题原因
问题本质是Set的等值判断逻辑导致的:
Set.prototype.has()方法使用严格相等(===) 做匹配判断- 字符串、数字等基础类型按值匹配,只要值相同就会判定为相等
- 对象类型按内存引用地址匹配,哪怕两个对象的所有属性值完全一致,只要是不同的引用(两次fetch返回的对象就是完全独立的引用),就会判定为不相等
因此代码中所有元素都会命中else分支被添加到Set中,最终呈现两个数组拼接的效果。
修复方案
需要将对象转换为可按值匹配的基础类型作为判断相等的依据,常用方案有两种:
方案1:基于唯一主键匹配(推荐,性能更高)
如果数组元素存在唯一标识字段(比如id、uuid),用该字段作为匹配依据:
let differenceDetector = (dataA, dataB) => { // 存储已出现的主键 const idSet = new Set(); // 存储最终差异对象 const diffList = []; // 遍历A数组,记录所有主键 for (const item of dataA) { idSet.add(item.id); diffList.push(item); } // 遍历B数组,对比主键 for (const item of dataB) { if (idSet.has(item.id)) { // 主键重复,从差异列表移除 diffList.splice(diffList.findIndex(i => i.id === item.id), 1); idSet.delete(item.id); } else { // 主键不存在,加入差异列表 diffList.push(item); idSet.add(item.id); } } return diffList; };
方案2:基于对象序列化匹配(无唯一主键时使用)
如果没有明确的唯一主键,可以把对象序列化后作为匹配依据,注意要保证对象属性顺序一致避免序列化结果不同:
let differenceDetector = (dataA, dataB) => { const compareMap = new Map(); // 遍历A数组,序列化后作为key存储 for (const item of dataA) { const key = JSON.stringify(item); compareMap.set(key, item); } // 遍历B数组对比 for (const item of dataB) { const key = JSON.stringify(item); if (compareMap.has(key)) { compareMap.delete(key); } else { compareMap.set(key, item); } } return Array.from(compareMap.values()); };
内容的提问来源于stack exchange,提问作者user16856118
相关产品推荐
相关产品推荐

