
本文将探讨如何在 JavaScript 中合并数组中的对象,特别是当这些对象拥有相同的日期或其他公共属性时。我们将分析一种常见的合并方法,指出其中潜在的陷阱,并提供更高效、简洁的替代方案。
问题分析:为何 Object.keys 和 hasOwnProperty 组合失效?
在尝试合并数组对象时,一个常见的错误出现在对 Object.keys 方法返回值的处理上。以下代码片段展示了这个问题:
var merged = [];cleaned.forEach(function(item) { var idx; var found = merged.some(function(el, i) { idx = el.date === item.date ? i : null; return el.date === item.date; }); if (!found) { merged.push(item); } else if (idx !== null) { console.log(Object.keys(item)) for (k in Object.keys(item)) { console.log(k) if (item.hasOwnProperty(k)) { merged[idx][k] = item[k]; } } }});
这段代码的目的是遍历数组 cleaned,如果 merged 数组中已存在具有相同 date 属性的对象,则将当前对象 item 的属性合并到已存在的对象中。然而,问题出在 for…in 循环中,Object.keys(item) 返回的是一个包含对象 item 所有键名的数组。因此,循环变量 k 取到的是数组的索引值(0, 1, 2, …),而不是对象 item 的键名。
由于 item 对象本身并不包含名为 “0”, “1”, “2” 等属性,item.hasOwnProperty(k) 始终返回 false,导致合并操作无法执行。
立即学习“Java免费学习笔记(深入)”;
解决方法:使用 for…of 循环
要解决这个问题,应该使用 for…of 循环来正确地迭代 Object.keys(item) 返回的键名数组:
for (let k of Object.keys(item)) { merged[idx][k] = item[k];}
使用 for…of 循环,变量 k 将会依次取到 item 对象的实际键名,从而允许正确地将属性合并到 merged 数组中的对应对象。
补充说明:hasOwnProperty 的必要性
在上述修正后的代码中,hasOwnProperty 已经不再是必需的。Object.keys 方法只会返回对象自身的可枚举属性,因此无需额外检查属性是否属于对象自身。
更简洁的替代方案:利用 Map 和 Object.assign
除了修正原有的代码,还可以使用 Map 和 Object.assign 提供一种更简洁、高效的解决方案。
const cleaned = [{data: {hours: ["2"],timeIn: ["2023-05-01T18:00:00Z"],timeOut: ["2023-05-01T20:00:00Z"],type: ["Client"]},date: "5/1/2023",entries: 2}, {data: {hours: [2, 2],timeIn: ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],timeOut: ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],type: ["Client"]},date: "5/10/2023",entries: 4}, {date: "5/1/2023",visits: 2}, {date: "5/10/2023",visits: 4}, {date: "5/1/2023",miles: 20}, {date: "5/10/2023",miles: 40}];const map = new Map(cleaned.map(item => [item.date, {}]));for (const item of cleaned) Object.assign(map.get(item.date), item);const merged = [...map.values()];console.log(merged);
这段代码首先使用 Map 对象创建一个以 date 属性为键,空对象为值的映射。然后,它遍历 cleaned 数组,使用 Object.assign 将每个对象的属性合并到 Map 中对应 date 属性的对象中。最后,将 Map 中的值转换为数组,得到合并后的结果。
代码解析:
创建 Map 对象: new Map(cleaned.map(item => [item.date, {}])) 使用 cleaned 数组创建一个 Map 对象,其中键为每个对象的 date 属性,值为一个空对象。这意味着对于每个不同的 date 值,Map 中都会创建一个对应的空对象。使用 Object.assign 合并属性: for (const item of cleaned) Object.assign(map.get(item.date), item); 遍历 cleaned 数组,对于每个对象 item,使用 map.get(item.date) 获取 Map 中与 item.date 对应的对象,然后使用 Object.assign 将 item 的所有属性合并到该对象中。Object.assign 会修改第一个参数(即 map.get(item.date) 返回的对象),将后续参数(即 item)的属性复制到第一个参数中。如果存在相同的属性名,则后续参数的属性值会覆盖第一个参数的属性值。将 Map 值转换为数组: const merged = […map.values()]; 使用扩展运算符 … 将 map.values() 返回的 Map 迭代器转换为数组。map.values() 返回一个包含 Map 对象中所有值的迭代器,这些值就是通过 Object.assign 合并后的对象。
总结:
使用 for…of 循环可以正确地迭代 Object.keys 返回的键名数组,避免因错误地使用索引值而导致属性合并失败。Map 和 Object.assign 提供了一种更简洁、高效的数组对象合并方案,尤其适用于需要基于公共属性进行合并的场景。
在实际开发中,应根据具体需求选择合适的合并方法。对于简单的合并操作,修正后的 for…in 循环可能已经足够。但对于更复杂的需求,Map 和 Object.assign 往往能提供更优雅、高效的解决方案。
以上就是JavaScript 数组对象合并:高效方法与常见问题的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/99694.html
微信扫一扫
支付宝扫一扫