如何合并两个对象的值

3
我有两个这样的对象,并想将它们合并:

const obj1 = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
};

const obj2 = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
};

const merged = someMergingMethod(obj1, obj2);

merged === {
  1: { foo: 1, bar: 2 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
};

我的意思是,我希望不仅合并对象本身,而且如果键重复,还要合并它们的属性值

因为使用merged = { ...obj1, ...obj2 };只会覆盖obj2的属性。

最简单的方法是什么?

我可以使用ES2017和其他库,如lodash。


1
可能是重复的问题:如何动态合并两个JavaScript对象的属性? - user5734311
1
不行,因为那个问题没有考虑合并属性。 - Taichi
如果 obj1.2.bar 是2但是 obj2.2.bar 是3,应该发生什么?无论如何,它都应该被关闭为“过于宽泛”,因为SO不是一个免费的代码编写服务。 - user5734311
可能是 https://dev59.com/clUL5IYBdhLWcg3wjIlQ 的重复问题。 - Naor Tedgi
对此我很抱歉 :( - Taichi
这个问题密切相关,但在那里他们正在合并数组中匹配的属性。 - Rodrigo Rodrigues
6个回答

6
您可以使用扩展运算符。
更新:
如果obj2有一些obj1没有的属性怎么办?
最初,我写这篇答案时假设键是索引的,例如0、1等。但是,正如您在评论中提到的那样,情况并非如此,因此您可以建立一个包含键的数组,然后遍历它,如下所示:
由@Nick在评论中简洁地添加:[...Object.keys(obj1), ...Object.keys(obj2)]

let obj1 = {1: { foo: 1 },2: { bar: 2, fooBar: 3 },3: { fooBar: 3 },};
let obj2 = {1: { foo: 1, bar: 2 },2: { bar: 2 },};

let keys = [...new Set([...Object.keys(obj1),...Object.keys(obj2)])]
let  op = {}
let merged = keys.forEach(key=>{
  op[key] = {
    ...obj1[key],
    ...obj2[key]
  }
})
console.log(op)


谢谢,但是如果obj2有一些obj1没有的属性怎么办?:( - Taichi
3
@Taichi,我不是这个答案的原作者,但我认为将Objects.keys(obj1).forEach更改为[...Object.keys(obj1), ...Object.keys(obj2)].forEach应该可以解决问题。 - Nick Parsons
1
@NickParsons 这太棒了,我正在编写一个函数来实现这个。谢谢伙计 :) - Code Maniac
2
@CodeManiac 不用担心,我有另一个想法,也许通过将键设置为 [...new Set([...Object.keys(obj1),...Object.keys(obj2)])]; 来消除重复会更好... 另外,我认为 merged 应该是 merged = keys.forEach() ;) - Nick Parsons

1

既然你提到了可以使用 lodash,你可以这样使用 merge

_.merge(obj1, obj2)

以获得你想要的结果。

请参见下面的工作示例:

const a = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
},

b = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
  4: {foo: 1}
},

res = _.merge(a, b);
console.log(res);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>


1

我有你想要的东西。该函数将遍历每个嵌套对象并将其与其他对象组合。我只在树下测试了5个嵌套级别,但从理论上讲,它应该适用于任何数量的嵌套对象,因为它是一个递归函数。

//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
    function combine(p, q)
    {
        for(i in q)
            if(!p.hasOwnProperty(i))
                p[i]= q[i];
        return p;
    }
    obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level 
    obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down theobjectt tree

//this function traverses each nested boject and combines it with the other object
    function traverse(a, b)
    {
        if(typeof(a) === "object" && typeof(b) === "object")
            for(i in b)
                if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
                    a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
                else
                    Object.assign(combine(a, b), a);
        return a;
    }
    return obj1;
}

console.log(merge(obj1, obj2));

这是一个更复杂的对象合并的工作示例。

var obj1 = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3, boor:{foob: 1, foof: 8} },
  4: {continent: {
    asia: {country: {india: {capital: "delhi"}, china: {capital: "beiging"}}},
    europe:{country:{germany: {capital: "berlin"},france: {capital: "paris"}}}
   },
   vegtables: {cucumber: 2, carrot: 3, radish: 7}
  }
};

var obj2 = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
  3: {fooBar: 3, boor:{foob: 1, boof: 6}, boob: 9 },
  4: {continent: {
    northamerica: {country: {mexico: {capital: "mexico city"}, canada: {capital: "ottawa"}},},
    asia: {country: {Afghanistan : {capital: "Kabul"}}}
   }
  },
  5: {barf: 42}
};

//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
 function combine(p, q)
 {
  for(i in q)
   if(!p.hasOwnProperty(i))
    p[i]= q[i];
  return p;
 }
 obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level 
 obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down the object tree

//this function traverses each nested boject and combines it with the other object
 function traverse(a, b)
 {
  if(typeof(a) === "object" && typeof(b) === "object")
   for(i in b)
    if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
     a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
    else
      Object.assign(combine(a, b), a);
  return a;
 }
 return obj1;
}

console.log(merge(obj1, obj2));


0

这可以通过巧妙地结合JavaScript的展开语法、数组和对象原型函数以及解构模式轻松实现。

[obj1,obj2].flatMap(Object.entries).reduce((o,[k,v])=>({...o,[k]:{...o[k],...v}}),{})

就这么简单!


如果想要了解这个是如何工作的详细解释,请参考类似问题的扩展回答


0

你可以使用 Object.assign 并将对象属性分配给空对象。

var a =  {books: 2};
var b = {notebooks: 1};
var c = Object.assign( {}, a, b );
console.log(c);

或者

您可以使用 Lodash 库中的 merge 方法。 可以在此处查看: https://www.npmjs.com/package/lodash


0
你是在寻找这样的吗?
我们可以用这种方式来合并两个对象。
const person = { name: 'David Walsh', gender: 'Male' };
const attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };
const summary = {...person, ...attributes};

/*

Object {
  "eyes": "Blue",
  "gender": "Male",
  "hair": "Brown",
  "handsomeness": "Extreme",
  "name": "David Walsh",
}

*/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接