Javascript 合并JS对象而不覆盖

Javascript 合并JS对象而不覆盖,javascript,merge,extend,deep-copy,Javascript,Merge,Extend,Deep Copy,假设您有两个对象: var foo = { a : 1, b : 2 }; var bar = { a : 3, b : 4 } 合并它们(并允许深度合并)的最佳方式是什么 var foobar = { a : [1, 3], b : [2, 4] } 编辑以澄清问题:理想情况下,在一个而不是另一个现有属性的情况下,我希望仍然会创建一个数组,用于规范化目的,并允许进一步缩小映射,但是我在下面看到的答案已经足够了。在本练习中,我只寻找字符串或数

假设您有两个对象:

var foo = {
    a : 1,
    b : 2
};

var bar = {
    a : 3,
    b : 4
}
合并它们(并允许深度合并)的最佳方式是什么

var foobar = {
    a : [1, 3],
    b : [2, 4]
}
编辑以澄清问题:理想情况下,在一个而不是另一个现有属性的情况下,我希望仍然会创建一个数组,用于规范化目的,并允许进一步缩小映射,但是我在下面看到的答案已经足够了。在本练习中,我只寻找字符串或数字合并,因此我没有考虑所有可能的情况。如果你拿枪指着我的头,让我做个选择,我会说默认为数组


感谢大家的贡献。

您可能会迭代一个对象,将其属性名称复制到新对象,并将值复制到分配给这些属性的数组中。迭代后续对象,如果属性和数组不存在,则添加它们,或者将它们的值添加到现有属性和数组中

e、 g


您可以通过迭代提供的参数来修改它以处理任意数量的对象,但这会使传递对象以合并为对象变得更加困难。

这应该满足您的要求。它将递归地将任意深度的对象合并到数组中

// deepmerge by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge(foo, bar) {
  var merged = {};
  for (var each in bar) {
    if (foo.hasOwnProperty(each) && bar.hasOwnProperty(each)) {
      if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
        merged[each] = deepmerge(foo[each], bar[each]);
      } else {
        merged[each] = [foo[each], bar[each]];
      }
    } else if(bar.hasOwnProperty(each)) {
      merged[each] = bar[each];
    }
  }
  for (var each in foo) {
    if (!(each in bar) && foo.hasOwnProperty(each)) {
      merged[each] = foo[each];
    }
  }
  return merged;
}
除了合并对象将包含继承属性的副本之外,这个对象也将执行相同的操作。这可能不是你想要的(根据RobG下面的评论),但如果这确实是你想要的,那么它就是:

// deepmerge_inh by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge_inh(foo, bar) {
  var merged = {};
  for (var each in bar) {
    if (each in foo) {
      if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
        merged[each] = deepmerge(foo[each], bar[each]);
      } else {
        merged[each] = [foo[each], bar[each]];
      }
    } else {
      merged[each] = bar[each];
    }
  }
  for (var each in foo) {
    if (!(each in bar)) {
      merged[each] = foo[each];
    }
  }
  return merged;
}
我用你的例子试了一下,效果很好:

deepmerge(foo, bar)
{"a": [1, 3], "b": [2, 4]}
bar
{"a": 3, "b": 4}
foo
{"a": 1, "b": 2}
稍微复杂一些的对象也可以工作:

deepmerge(as, po)
{"a": ["asdf", "poui"], "b": 4, "c": {"q": [1, 444], "w": [function () {return 5;}, function () {return 1123;}]}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
po
{"a": "poui", "c": {"q": 444, "w": function () {return 1123;}}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
as
{"a": "asdf", "b": 4, "c": {"q": 1, "w": function () {return 5;}}}

//使用自定义程序回调
变量对象={
“水果”:[“苹果”],
“蔬菜”:[“甜菜”]
};
其他变量={
“水果”:[“香蕉”],
“蔬菜”:[“胡萝卜”]
};
_.合并(对象、其他、函数(a、b){
如果(uu.isArray(a)){
返回a.concat(b);
}
});

// → {‘水果’:[‘苹果’、‘香蕉’、‘蔬菜’:[‘甜菜’、‘胡萝卜’]}
我认为这是显而易见的,而不是问题所要求的,那么你的答案是什么?OP中没有关于如何处理深度合并的任何内容,可能会在响应中透露更多信息…@Walkereno-假设OP不想复制继承的属性,也不想将它们添加到继承的属性(如果可能)提供的对象中。@Walkereno,
hasOwnProperty
只是确保它不是继承的属性。然后我收回我的语句。我去查一下什么是继承财产。编辑:好的,很抱歉。我忘了。如果foo有一个属性
c:5
,但bar没有。。。foobar是否直接从foo复制属性?或者它有
c:[5]
?你只对自己的财产感兴趣还是对继承的财产感兴趣?我注意到您用jQuery和extend标记了它。您是否认为解决方案使用
jquery.extend
作为基础?您应该更具体地说明针对您要求说明的各种情况希望发生什么。深度合并是什么意思?RobG的答案似乎正是你想要的,在第一个答案之后去掉一个
}
,但除此之外,效果很好。谢谢,谢谢!抢手货很抱歉。我在复制/粘贴到jsconsole时修复了它,但忘了将其返回到另一个缓冲区。再次感谢您指出这一点——我已经解决了:)我希望一个合并“对象到数组”的函数为每个属性都有一个数组,而不是字符串、对象、函数等的混合。它也不会筛选出固有属性,也不会处理具有自己属性的函数。如果要合并两个类型完全不同的对象,那么您可能实际上希望合并结果中包含继承的属性。而且,我看不出处理函数如何增加此解决方案中的价值。听起来这将是一个更具体的解决方案,我的目标是一个更通用的解决方案,只是工作。如果您需要该功能,那么修改上述代码以实现所需功能并不困难。我只是想回答这个问题,不做任何假设:)@Zach-OP没有说应该或不应该处理什么类型的对象。指出限制或假设是个好主意,这样OP可以做出更明智的评估。至于继承属性,复制它们似乎不是一个好主意(但同样,没有明确的要求)。我知道这个答案需要安装Lodash,但我不明白为什么需要否决它。这是唯一对我有用的,也是最干净的!
deepmerge(as, po)
{"a": ["asdf", "poui"], "b": 4, "c": {"q": [1, 444], "w": [function () {return 5;}, function () {return 1123;}]}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
po
{"a": "poui", "c": {"q": 444, "w": function () {return 1123;}}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
as
{"a": "asdf", "b": 4, "c": {"q": 1, "w": function () {return 5;}}}