不同数据源数组对象filter过滤失效,求替代实现方法
问题分析与解决方案
你猜的完全没错!问题核心就是对象的引用差异——indexOf()方法使用严格相等运算符(===)来判断元素是否存在于数组中。哪怕两个对象的键值对完全一致,只要它们是不同的引用(比如来自不同数据库的查询结果,是各自独立创建的对象),就会被判定为不相等,所以indexOf(e)才会返回-1。而你用.push()添加的数据能正常过滤,是因为添加的是同一个对象引用,自然能被indexOf识别到。
针对这个问题,有两种常用的解决思路,根据你的场景选择即可:
1. 基于唯一标识过滤(推荐)
你的对象里有_id这个天然的唯一标识,这是最高效的解决方案:
// 先把yin数组中所有对象的_id提取到Set中,Set的查找效率是O(1) const yinIds = new Set(yin.map(item => item._id)); // 过滤yang数组,保留_id不在yinIds中的元素 const filteredYang = yang.filter(item => !yinIds.has(item._id));
这种方法的优势是性能优异,尤其是当数组元素数量较多时,比遍历比较整个对象要快得多。
2. 比较对象的所有键值对(无唯一标识时使用)
如果你的对象没有像_id这样的唯一标识,就需要编写一个辅助函数来深度比较两个对象的内容是否一致,再进行过滤:
// 辅助函数:深度比较两个对象的内容是否相等 function isContentEqual(objA, objB) { // 引用相同直接返回true if (objA === objB) return true; // 非对象类型或null直接比较值 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return objA === objB; } // 比较键的数量 const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) return false; // 逐个比较键对应的值(递归处理嵌套对象) for (const key of keysA) { if (!keysB.includes(key) || !isContentEqual(objA[key], objB[key])) { return false; } } return true; } // 过滤yang数组:保留yin中没有匹配内容的元素 const filteredYang = yang.filter(yangItem => { return !yin.some(yinItem => isContentEqual(yinItem, yangItem)); });
注意:这种方法的性能会随着数组大小和对象复杂度下降,所以优先推荐第一种基于唯一标识的方案。
内容的提问来源于stack exchange,提问作者bryan
相关产品推荐
相关产品推荐

