将两个嵌套对象组合在一起,同时保留两者的属性,同时将重复键值一起添加

问题描述 投票:1回答:3

我已经看过几篇关于将两个对象合并在一起的帖子,但大多数都是用于合并包含不包含嵌套元素的对象的对象。当我实现一个建议的解决方案时,将覆盖一个对象的属性。

const Gnome = () => {
  return {
    ExpRate: .20,
    Abilities: {
      PickDoors: 1,
    },
    Buffs: {
      NightSight: 65, 
      MagicRes: 5, 
    },
    ... Additional data and behaviors
  };
}

const Thief = () {
  return {
    ExpRate: 2.10, 
    Abilities: {
      Thievery: 1,
      PickDoors: 1, 
    },
    Buffs: {}, 
    // ... Additional data and behavors
  };
}

我一直在尝试将这两个对象合并为:

{
 ExpRate: 2.30,
 Abilities: {
    PickDoors: 2,
    Thievery: 1
 }, 
 Buffs: {
    NightSight: 65,
    MagicRes: 5, 
 }, 
// ... Additional data and behavors from both objects
};

但是,使用Object.assign将覆盖现有键中的值,从而丢失数据。 IE:

const myGnome = Gnome();
const myThief = Thief();
const myPlayer = Object.assign({}, myGnome, myThief);

我已经尝试了一些人们发布的建议合并方法,但它们似乎都与Object.assign();任何建议,将不胜感激。如果这实际上是一个重复的帖子,我会喜欢它的链接。

提前致谢。

javascript
3个回答
2
投票

您可以迭代条目并检查是否找到了对象,然后再次为嵌套对象调用该函数。如果找到数字,请添加此值。

function merge(a, b) {
    function mergeTo(source, target) {
        Object.entries(source).forEach(([k, v]) => {
            if (Array.isArray(v)) {
                target[k] = target[k] || [];
                target[k].push(...v);
                return;
            }
            if (v && typeof v === 'object') {
                mergeTo(v, target[k] = target[k] || {});
                return;
            }
            if (typeof v === 'number') { 
                target[k] = (target[k] || 0) + v;
                return;
            }
            if (!(k in target)) {
                target[k] = v;
                return;
            }
            target[k] = Array.isArray(target[k])
                ? [...target[k], v]
                : [target[k], v];
        });
    }

    var object = {};
    mergeTo(a, object);
    mergeTo(b, object);
    return object;
}

console.log(merge(
    { ExpRate: .20, Abilities: { PickDoors: 1 }, Buffs: { NightSight: 65, MagicRes: 5 }, array: [1, 2], v: 'a' },
    { ExpRate: 2.10, Abilities: { Thievery: 1, PickDoors: 1 }, Buffs: {}, array: [3, 4], v: 'b', f: true }
));
.as-console-wrapper { max-height: 100% !important; top: 0; }

1
投票

你可以使用递归来做到这一点。以下是示例

const Gnome = () => {
  return ({
    ExpRate: .20,
    Abilities: {
      PickDoors: 1,
    },
    Buffs: {
      NightSight: 65, 
      MagicRes: 5, 
    }
  });
}

const Thief = () => {
  return ({
    ExpRate: 2.10, 
    Abilities: {
      Thievery: 1,
      PickDoors: 1, 
    },
	Buffs:{}
  });
}
let thief = Thief();
let gnone = Gnome();




function merge(obj1,obj2){
	let keys1 = Object.keys(obj1);
	let keys2 = Object.keys(obj2);
	let objToReturn = Object.assign({},obj1,obj2);
	let sameKeys = [... new Set(keys1.filter(key => keys2.includes(key)).concat(keys2.filter(key => keys1.includes(key))))]
	sameKeys.forEach(key => {
		if(typeof obj1[key] === "object") objToReturn[key] = merge(obj1[key],obj2[key]);
		else objToReturn[key] = obj2[key] + obj1[key];
	})
	return objToReturn;
	
}
console.log(merge(thief,gnone));

0
投票

谢谢你的回复。我会给你的建议一个。我能够按照建议编写一个函数:

    function isObject(item) {
      return (item && typeof item === 'object' && !Array.isArray(item));
    }

    function mergeDeep(target, source) {
      let output = Object.assign({}, target);
      if (isObject(target) && isObject(source)) {
        Object.keys(source).forEach(key => {
          if (isObject(source[key])) {
            if (!(key in target))
              Object.assign(output, { [key]: source[key] });
            else
              output[key] = mergeDeep(target[key], source[key]);
          } else {
              if(typeof target[key] === 'number' && typeof source[key] === 'number'){
                  source[key] += target[key];
              }

            Object.assign(output, { [key]: source[key] });
          }
        });
      }
      return output;
    }
    console.log(
      mergeDeep(
        {ExpRate: .20, Abilities: {PickDoors: 1}, Buffs: {NightSight: 65, MagicRes: 5}}, 
        {ExpRate: 2.10, Abilities: {Thievery: 1, PickDoors: 1}}
    ));

我会提出其他建议,因为我担心上述方法可能会有点复杂并导致将来出现问题。

© www.soinside.com 2019 - 2024. All rights reserved.