JS算法问题排查:whatIsInAName函数不符合预期的原因分析
函数whatIsInAName错误原因排查
需求与问题场景
我们需要实现whatIsInAName函数:接收对象数组collection(第一个参数)和源对象source(第二个参数),返回所有完全包含source全部键值对的对象。
在测试用例:
whatIsInAName([{ apple: 1, bat: 2 }, { bat: 2 }, { apple: 1, bat: 2, cookie: 2 }], { apple: 1, bat: 2 })
中,错误代码返回了全部3个对象,但正确结果应为[{ "apple": 1, "bat": 2, "cookie": 2 }]。
错误代码
function whatIsInAName(collection, source) { const arr = []; collection.filter(function (obj) { const objKeysInSrc = Object.keys(source); objKeysInSrc.every(function (keyVal) { console.log(keyVal); console.log(obj[keyVal]); console.log(source[keyVal]); console.log(obj.hasOwnProperty(keyVal)); if (obj.hasOwnProperty(keyVal) && obj[keyVal] === source[keyVal]) { console.log("match"); arr.push(obj); } }); }); console.log(arr); return arr; }
正确代码
function whatIsInAName(collection, source) { const filtArr = collection .filter(prop => Object.keys(source) .every(value => prop .hasOwnProperty(value) && prop[value] === source[value])); return filtArr; }
错误代码的核心问题
filter函数被误用filter需要回调函数返回布尔值,以此决定是否保留当前元素。但错误代码里的filter回调没有返回任何值(默认返回undefined,等价于false),所以filter根本没起到筛选作用,只是被用来遍历数组。every的逻辑完全错误every的设计是:只有当数组所有元素都满足回调条件时,才返回true;只要有一个元素不满足,就停止遍历并返回false。但错误代码在every的回调里,只要单个键值对匹配就把对象推入数组,这会导致:- 第一个测试对象
{ apple: 1, bat: 2 },遍历source的两个键时,每个键匹配都会执行一次arr.push(obj),最终这个对象被推入两次; - 第二个测试对象
{ bat: 2 },虽然缺少apple键,但遍历到bat键匹配时,依然会被推入数组;
最终数组里既包含不符合要求的对象,还有重复项。
- 第一个测试对象
未满足“全部键值对匹配”的核心要求
需求要求对象必须包含source的所有键值对,但错误代码没有判断这一点——只要有一个键值对匹配就保留对象,完全忽略了“全部匹配”的约束。
正确代码的逻辑合理性
正确代码通过链式调用严格实现了需求:
- 用
filter遍历collection的每个对象; - 对每个对象,先获取
source的所有键,再用every验证:当前对象是否拥有所有这些键,且每个键对应的值都和source相等; - 只有当
every返回true(即所有键值对都匹配)时,filter才会保留该对象,最终得到符合要求的结果。
内容的提问来源于stack exchange,提问作者myles luke
相关产品推荐
相关产品推荐

