最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Merge JS objects without overwriting - Stack Overflow

programmeradmin0浏览0评论

Suppose you have two objects:

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

var bar = {
    a : 3,
    b : 4
}

What's the best way to merge them (and allow deep merging) to create this:

var foobar = {
    a : [1, 3],
    b : [2, 4]
}

Edit for question clarification: Ideally, in the case of an existing property in one and not the other, I would expect an array to still be created, for normalization purposes and to allow for further reduction of the map, however the answers I'm seeing below are more than sufficient. For the purposes of this exercise, I was only looking for string or numerical merges, so I hadn't entertained every possible situational case. If you held a gun to my head and asked me to make a choice, though, I'd say default to arrays.

Thanks all for your contributions.

Suppose you have two objects:

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

var bar = {
    a : 3,
    b : 4
}

What's the best way to merge them (and allow deep merging) to create this:

var foobar = {
    a : [1, 3],
    b : [2, 4]
}

Edit for question clarification: Ideally, in the case of an existing property in one and not the other, I would expect an array to still be created, for normalization purposes and to allow for further reduction of the map, however the answers I'm seeing below are more than sufficient. For the purposes of this exercise, I was only looking for string or numerical merges, so I hadn't entertained every possible situational case. If you held a gun to my head and asked me to make a choice, though, I'd say default to arrays.

Thanks all for your contributions.

Share Improve this question edited Sep 26, 2011 at 9:54 Zachary Murray 1,2209 silver badges16 bronze badges asked Sep 26, 2011 at 0:26 dclowd9901dclowd9901 6,8269 gold badges46 silver badges64 bronze badges 3
  • 3 If foo has a property c:5 but bar does not... does foobar have the property copied directly from foo? or does it have c:[5]? – scunliffe Commented Sep 26, 2011 at 0:32
  • Are you interested only in own properties or inherited properties too? And I noticed you tagged it with jQuery and extend. Are you thinking a solution uses jquery.extend as a basis? – Ray Toal Commented Sep 26, 2011 at 0:36
  • You should be a bit more specific with what you want to happen for the various cases you're asking to account for. What do you mean deep merging? RobG's answer seems like exactly what you want – mowwwalker Commented Sep 26, 2011 at 0:39
Add a comment  | 

4 Answers 4

Reset to default 10

This ought to do what you're looking for. It will recursively merge arbitrarily deep objects into arrays.

// 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;
}

And this one will do the same, except that the merged object will include copies of inherited properties. This probably isn't what you're looking for (as per RobG's comments below), but if that is actually what you are looking for, then here it is:

// 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;
}

I tried it out with your example on http://jsconsole.com, and it worked fine:

deepmerge(foo, bar)
{"a": [1, 3], "b": [2, 4]}
bar
{"a": 3, "b": 4}
foo
{"a": 1, "b": 2}

Slightly more complicated objects worked as well:

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;}}}

Presumably you would iterate over one object and copy its property names to a new object and values to arrays assigned to those properties. Iterate over subsequent objects, adding properties and arrays if they don't already exist or adding their values to existing properties and arrays.

e.g.

function mergeObjects(a, b, c) {
  c = c || {};
  var p;

  for (p in a) {
    if (a.hasOwnProperty(p)) {
      if (c.hasOwnProperty(p)) {
        c[p].push(a[p]);
      } else {
        c[p] = [a[p]];
      }
    }
  }
  for (p in b) {
    if (b.hasOwnProperty(p)) {
      if (c.hasOwnProperty(p)) {
        c[p].push(b[p]);
      } else {
        c[p] = [b[p]];
      }
    }
  }
  return c;
}

You could modify it to handle any number of objects by iterating over the arguments supplied, but that would make passing the object to merge into more difficult.

https://lodash.com/docs/3.10.1#merge

    // using a customizer callback
var object = {
  'fruits': ['apple'],
  'vegetables': ['beet']
};

var other = {
  'fruits': ['banana'],
  'vegetables': ['carrot']
};

_.merge(object, other, function(a, b) {
  if (_.isArray(a)) {
    return a.concat(b);
  }
});
// → { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }

I just leave it here. Shallow merging with values as arrays.

const foo = {a: 1, b: 2}
const bar = {a: 2, с: 4}
const baz = {a: 3, b: 3}

const myMerge = (...args) => args
  .flatMap(Object.entries)
  .reduce((acc, [key, value]) => {
    acc[key] ??= []
    acc[key].push(value)
    return acc
  }, {})

console.log(myMerge(foo, bar, baz))
//{ a: [1, 2, 3],
//  b: [2, 3],
//  с: [4] }
.as-console-wrapper { max-height: 100% !important; top: 0 }

发布评论

评论列表(0)

  1. 暂无评论