遍历mapObject设置'on'属性时仅最后一个对象被更新的原因
问题:为对象数组添加匹配状态属性时结果不符合预期
我有两个数据结构:
- 一个是包含ID的数组
value,结构类似:[1, 3, 5](或对象数组[{id:1}, {id:3}, {id:5}]) - 另一个是对象数组
mapObject,每个元素都有id属性,结构类似:
[ { id: 1, name: "Item 1" }, { id: 2, name: "Item 2" }, { id: 3, name: "Item 3" }, { id: 4, name: "Item 4" } ]
我的目标是编写函数遍历mapObject,当元素的id匹配value中的任意元素时,为该元素新增on属性并设为true,否则设为false。
我的实现代码
function addOnProperty(mapObject, value) { mapObject.forEach(item => { item.on = value.indexOf(item.id) > -1; }); return mapObject; } // 调用示例 const value = [{id:1}, {id:3}, {id:5}]; const mapObject = [ { id: 1, name: "Item 1" }, { id: 2, name: "Item 2" }, { id: 3, name: "Item 3" }, { id: 4, name: "Item 4" } ]; const result = addOnProperty(mapObject, value); console.log(result);
预期结果
[ { id: 1, name: "Item 1", on: true }, { id: 2, name: "Item 2", on: false }, { id: 3, name: "Item 3", on: true }, { id: 4, name: "Item 4", on: false } ]
实际运行结果
[ { id: 1, name: "Item 1", on: false }, { id: 2, name: "Item 2", on: false }, { id: 3, name: "Item 3", on: false }, { id: 4, name: "Item 4", on: false } ]
请问为什么会出现这种情况?
回答
嘿,我来帮你揪出问题根源!这种结果不符合预期的情况,大概率是匹配逻辑的判断方式和你的数据结构不匹配,咱们一步步拆解:
你现在用的value.indexOf(item.id)是严格相等(===)匹配,但如果你的value是对象数组(比如[{id:1}, {id:3}, {id:5}]),拿数字item.id和整个对象去比较,肯定不可能相等,所以indexOf永远返回-1,最终所有on属性都是false。
另外还有一种常见情况:如果value是普通ID数组,但item.id的类型和value里的元素类型不一致(比如item.id是字符串"1",value里是数字1),indexOf也会因为类型不匹配返回-1。
针对性的修正方案
方案1:如果value是对象数组
改用Array.some()方法,专门用来判断数组中是否存在满足条件的元素:
function addOnProperty(mapObject, value) { mapObject.forEach(item => { // 遍历value数组,判断是否有id匹配的元素 item.on = value.some(v => v.id === item.id); }); return mapObject; }
方案2:如果value是普通ID数组
先统一类型,或者直接用Array.includes()(和indexOf逻辑一致,但写法更直观):
function addOnProperty(mapObject, value) { mapObject.forEach(item => { // 统一类型后再判断,比如把item.id转成数字 item.on = value.includes(Number(item.id)); }); return mapObject; }
进阶优化:提升大数组的匹配效率
如果你的value数组元素很多,每次遍历都用some()或includes()会有点慢,建议先把value里的ID转成Set,这样查找速度能从O(n)降到O(1):
function addOnProperty(mapObject, value) { // 先把所有需要匹配的ID存入Set const targetIds = new Set(value.map(v => v.id)); // 对象数组的情况 // 如果是普通ID数组,直接写 const targetIds = new Set(value); mapObject.forEach(item => { item.on = targetIds.has(item.id); }); return mapObject; }
这样修改后,就能得到你预期的结果啦!
内容的提问来源于stack exchange,提问作者Dallas Caley
相关产品推荐
相关产品推荐

