编写可合并任意数量对象并保留首次出现键值的函数——问题排查与修正
解决对象合并时保留首次出现键值的问题
我懂你的需求:你需要一个能合并任意数量对象的函数,而且当多个对象有相同键名时,要保留第一次出现的那个值。但你当前用Object.assign的写法刚好和预期相反,因为Object.assign()的特性是后面的对象会覆盖前面对象的同名属性——这就是为什么你的测试里foo最终变成了13,而不是你想要的5。
修正后的函数实现
我们需要换个思路:按顺序遍历所有传入的对象,只把结果对象里还没有的键加进去。这样就能保证先出现的键值不会被后续的同名键覆盖。
写法一:基础循环版
function zip(...objects) { const mergedObj = {}; // 逐个处理每个传入的对象 for (const obj of objects) { // 遍历当前对象的所有自有键 for (const key of Object.keys(obj)) { // 只有当键还没在结果对象里时,才添加 if (!(key in mergedObj)) { mergedObj[key] = obj[key]; } } } return mergedObj; }
写法二:用reduce简化版
如果你喜欢更简洁的函数式写法,也可以用Array.reduce来实现:
function zip(...objects) { return objects.reduce((merged, currentObj) => { Object.keys(currentObj).forEach(key => { if (!(key in merged)) { merged[key] = currentObj[key]; } }); return merged; }, {}); }
测试验证
用你的示例测试一下:
const objects = [ { foo: 5, bar: 6 }, { foo: 13, baz: -1 } ]; console.log(zip(...objects)); // 输出:{ foo: 5, bar: 6, baz: -1 }
完全符合你的预期!
为什么原写法不行?
再强调一下:Object.assign({}, ...objects)会把objects数组里的对象按顺序传入assign,也就是先合并第一个对象,再用第二个对象的属性去覆盖第一个的同名属性——这和你要的"保留首次值"逻辑刚好相反,所以才会得到错误的结果。
内容的提问来源于stack exchange,提问作者Mr.Mox
相关产品推荐
相关产品推荐

