如何检测嵌套对象的全部键值对是否存在于目标对象数组中(含Jest实现)
解决方案
方法1:Jest 内置匹配器实现(推荐,无需额外工具)
你之前的Jest写法无法生效,是因为直接传入了普通obj对象,Jest会对obj的messages数组做全等匹配,要求内部对象的所有属性完全一致,自然无法匹配缺省date的情况。
Jest的expect.objectContaining、expect.arrayContaining支持任意层级嵌套,直接嵌套声明部分匹配规则即可:
expect(data).toEqual( expect.arrayContaining([ expect.objectContaining({ region: "London", airport: "Heathrow", // 内层messages数组声明部分匹配规则 messages: expect.arrayContaining([ expect.objectContaining({ region: "London", message: "This is a test message" }) ]) }) ]) )
如果要求messages数组的长度和顺序也和obj完全一致,仅内部对象允许缺省属性,可以把内层的expect.arrayContaining换成普通数组,内部元素依然用expect.objectContaining声明:
expect(data).toEqual( expect.arrayContaining([ expect.objectContaining({ region: "London", airport: "Heathrow", messages: [ expect.objectContaining({ region: "London", message: "This is a test message" }) ] }) ]) )
方法2:原生JS实现通用深度包含函数
如果需要在非Jest场景下使用,可以写一个递归的深度匹配函数:
// 判断target是否完全包含source的所有键值对(允许target有额外属性) function deepContains(source, target) { // 基础类型直接全等判断 if (source === null || typeof source !== 'object') { return source === target } // 数组类型判断 if (Array.isArray(source)) { if (!Array.isArray(target) || source.length > target.length) return false // 可根据需求调整:当前规则为source每个元素都能在target中找到对应匹配项(不要求顺序) return source.every(sItem => target.some(tItem => deepContains(sItem, tItem))) // 如果要求顺序一致,替换为: // return source.every((sItem, index) => deepContains(sItem, target[index])) } // 对象类型判断 const sourceKeys = Object.keys(source) return sourceKeys.every(key => { return Object.prototype.hasOwnProperty.call(target, key) && deepContains(source[key], target[key]) }) } // 使用方式 const exists = data.some(item => deepContains(obj, item)) console.log(exists) // 存在匹配项则返回true
注意你最开始写的原生JS逻辑有错误:判断
obj的所有键都匹配需要用every而不是some,some只要有一个键匹配就返回true,不符合需求。
内容的提问来源于stack exchange,提问作者craig-nerd
相关产品推荐
相关产品推荐

