Объединение объектов JS без перезаписи - PullRequest
8 голосов
/ 26 сентября 2011

Предположим, у вас есть два объекта:

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

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

Как лучше всего объединить их (и разрешить глубокое объединение), чтобы создать это:

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

Изменить на вопросуточнение: В идеале, в случае существующего свойства в одном, а не в другом, я бы ожидал, что массив все еще будет создан, для целей нормализации и для дальнейшего уменьшения карты, однако ответы явидя ниже, более чем достаточно.Для целей этого упражнения я искал только строковые или числовые слияния, поэтому не рассматривал каждый возможный ситуационный случай.Если бы вы приставили пистолет к моей голове и попросили меня сделать выбор, я бы сказал, по умолчанию для массивов.

Спасибо всем за ваш вклад.

Ответы [ 3 ]

9 голосов
/ 26 сентября 2011

Это должно делать то, что вы ищете. Он будет рекурсивно объединять произвольно глубокие объекты в массивы.

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

Я попробовал это на вашем примере на http://jsconsole.com,, и он работал нормально:

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;}}}
3 голосов
/ 26 сентября 2011

Предположительно, вы бы перебрали один объект и скопировали имена его свойств в новый объект и значения в массивы, назначенные этим свойствам.Выполните итерацию по последующим объектам, добавляя свойства и массивы, если они еще не существуют, или добавляя их значения к существующим свойствам и массивам.

например,

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

Вы можете изменить его для обработки любого числаобъектов путем итерации по предоставленным аргументам, но это сделает передачу объекта для слияния более сложной.

0 голосов
/ 11 декабря 2015

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'] }
...